diff options
author | 2022-06-17 23:18:18 -0700 | |
---|---|---|
committer | 2022-06-22 06:56:47 -0700 | |
commit | be9efacf1bf03fba016bb02f1dd25766fd874033 (patch) | |
tree | 9a13f40cb442e3e5d005c5f5b6112b05e626f1c1 /src | |
parent | 71025c8bcc68929cea2260d92de03e20a3c898d2 (diff) | |
download | bun-be9efacf1bf03fba016bb02f1dd25766fd874033.tar.gz bun-be9efacf1bf03fba016bb02f1dd25766fd874033.tar.zst bun-be9efacf1bf03fba016bb02f1dd25766fd874033.zip |
WebSocket is a global
Diffstat (limited to 'src')
22 files changed, 334 insertions, 266 deletions
diff --git a/src/deps/uws.zig b/src/deps/uws.zig index 1fbce62c5..3d3629bcb 100644 --- a/src/deps/uws.zig +++ b/src/deps/uws.zig @@ -17,7 +17,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type { const ThisSocket = @This(); pub fn isEstablished(this: ThisSocket) bool { - return us_socket_is_established(comptime ssl_int, this.socket); + return us_socket_is_established(comptime ssl_int, this.socket) > 0; } pub fn timeout(this: ThisSocket, seconds: c_uint) void { @@ -48,7 +48,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type { comptime ssl_int, this.socket, data.ptr, - data.len, + @intCast(c_int, data.len), @as(c_int, @boolToInt(msg_more)), ); } @@ -77,7 +77,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type { ); } pub fn close(this: ThisSocket, code: c_int, reason: ?*anyopaque) void { - return us_socket_close( + _ = us_socket_close( comptime ssl_int, this.socket, code, @@ -109,7 +109,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type { ) ?*Context { var stack_fallback = std.heap.stackFallback(1024, bun.default_allocator); var allocator = stack_fallback.get(); - var host_ = allocator.dupeZ(u8, host) orelse return null; + var host_ = allocator.dupeZ(u8, host) catch return null; defer allocator.free(host_); var socket = us_socket_context_connect(comptime ssl_int, socket_ctx, host_, port, null, 0, @sizeOf(Context)) orelse return null; @@ -136,10 +136,10 @@ pub fn NewSocketHandler(comptime ssl: bool) type { comptime onEnd: anytype, ) void { const SocketHandler = struct { - pub fn on_open(socket: *Socket, _: c_int, ip: [*:0]u8, port: c_int) callconv(.C) ?*Socket { + pub fn on_open(socket: *Socket, _: c_int, ip: [*c]u8, port: c_int) callconv(.C) ?*Socket { onOpen( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, + ThisSocket{ .socket = socket }, bun.span(ip), port, ); @@ -148,7 +148,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type { pub fn on_close(socket: *Socket, code: c_int, reason: ?*anyopaque) callconv(.C) ?*Socket { onClose( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, + ThisSocket{ .socket = socket }, code, reason, ); @@ -157,29 +157,29 @@ pub fn NewSocketHandler(comptime ssl: bool) type { pub fn on_data(socket: *Socket, buf: ?[*]u8, len: c_int) callconv(.C) ?*Socket { onData( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, - buf.?[0..len], + ThisSocket{ .socket = socket }, + buf.?[0..@intCast(usize, len)], ); return socket; } pub fn on_writable(socket: *Socket) callconv(.C) ?*Socket { onWritable( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, + ThisSocket{ .socket = socket }, ); return socket; } pub fn on_timeout(socket: *Socket) callconv(.C) ?*Socket { onTimeout( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, + ThisSocket{ .socket = socket }, ); return socket; } pub fn on_connect_error(socket: *Socket, code: c_int) callconv(.C) ?*Socket { onConnectError( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, + ThisSocket{ .socket = socket }, code, ); return socket; @@ -187,7 +187,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type { pub fn on_end(socket: *Socket) callconv(.C) ?*Socket { onEnd( @ptrCast(*ContextType, @alignCast(std.meta.alignment(ContextType), us_socket_ext(comptime ssl_int, socket).?)), - socket, + ThisSocket{ .socket = socket }, ); return socket; } @@ -289,23 +289,23 @@ extern fn us_socket_context_on_server_name(ssl: c_int, context: ?*us_socket_cont extern fn us_socket_context_get_native_handle(ssl: c_int, context: ?*us_socket_context_t) ?*anyopaque; extern fn us_create_socket_context(ssl: c_int, loop: ?*Loop, ext_size: c_int, options: us_socket_context_options_t) ?*us_socket_context_t; extern fn us_socket_context_free(ssl: c_int, context: ?*us_socket_context_t) void; -extern fn us_socket_context_on_open(ssl: c_int, context: ?*us_socket_context_t, on_open: fn (?*Socket, c_int, [*c]u8, c_int) callconv(.C) ?*Socket) void; -extern fn us_socket_context_on_close(ssl: c_int, context: ?*us_socket_context_t, on_close: fn (?*Socket, c_int, ?*anyopaque) callconv(.C) ?*Socket) void; -extern fn us_socket_context_on_data(ssl: c_int, context: ?*us_socket_context_t, on_data: fn (?*Socket, [*c]u8, c_int) callconv(.C) ?*Socket) void; +extern fn us_socket_context_on_open(ssl: c_int, context: ?*us_socket_context_t, on_open: fn (*Socket, c_int, [*c]u8, c_int) callconv(.C) ?*Socket) void; +extern fn us_socket_context_on_close(ssl: c_int, context: ?*us_socket_context_t, on_close: fn (*Socket, c_int, ?*anyopaque) callconv(.C) ?*Socket) void; +extern fn us_socket_context_on_data(ssl: c_int, context: ?*us_socket_context_t, on_data: fn (*Socket, [*c]u8, c_int) callconv(.C) ?*Socket) void; extern fn us_socket_context_on_writable(ssl: c_int, context: ?*us_socket_context_t, on_writable: fn (*Socket) callconv(.C) ?*Socket) void; -extern fn us_socket_context_on_timeout(ssl: c_int, context: ?*us_socket_context_t, on_timeout: fn (?*Socket) callconv(.C) ?*Socket) void; -extern fn us_socket_context_on_connect_error(ssl: c_int, context: ?*us_socket_context_t, on_connect_error: fn (?*Socket, c_int) callconv(.C) ?*Socket) void; -extern fn us_socket_context_on_end(ssl: c_int, context: ?*us_socket_context_t, on_end: fn (?*Socket) callconv(.C) ?*Socket) void; +extern fn us_socket_context_on_timeout(ssl: c_int, context: ?*us_socket_context_t, on_timeout: fn (*Socket) callconv(.C) ?*Socket) void; +extern fn us_socket_context_on_connect_error(ssl: c_int, context: ?*us_socket_context_t, on_connect_error: fn (*Socket, c_int) callconv(.C) ?*Socket) void; +extern fn us_socket_context_on_end(ssl: c_int, context: ?*us_socket_context_t, on_end: fn (*Socket) callconv(.C) ?*Socket) void; extern fn us_socket_context_ext(ssl: c_int, context: ?*us_socket_context_t) ?*anyopaque; extern fn us_socket_context_listen(ssl: c_int, context: ?*us_socket_context_t, host: [*c]const u8, port: c_int, options: c_int, socket_ext_size: c_int) ?*listen_socket_t; -extern fn us_socket_context_connect(ssl: c_int, context: ?*us_socket_context_t, host: [*c]const u8, port: c_int, source_host: [*c]const u8, options: c_int, socket_ext_size: c_int) ?*Socket; -extern fn us_socket_is_established(ssl: c_int, s: ?*Socket) c_int; -extern fn us_socket_close_connecting(ssl: c_int, s: ?*Socket) ?*Socket; -extern fn us_socket_context_loop(ssl: c_int, context: ?*us_socket_context_t) ?*Loop; -extern fn us_socket_context_adopt_socket(ssl: c_int, context: ?*us_socket_context_t, s: ?*Socket, ext_size: c_int) ?*Socket; -extern fn us_create_child_socket_context(ssl: c_int, context: ?*us_socket_context_t, context_ext_size: c_int) ?*us_socket_context_t; +pub extern fn us_socket_context_connect(ssl: c_int, context: ?*us_socket_context_t, host: [*c]const u8, port: c_int, source_host: [*c]const u8, options: c_int, socket_ext_size: c_int) ?*Socket; +pub extern fn us_socket_is_established(ssl: c_int, s: ?*Socket) c_int; +pub extern fn us_socket_close_connecting(ssl: c_int, s: ?*Socket) ?*Socket; +pub extern fn us_socket_context_loop(ssl: c_int, context: ?*us_socket_context_t) ?*Loop; +pub extern fn us_socket_context_adopt_socket(ssl: c_int, context: ?*us_socket_context_t, s: ?*Socket, ext_size: c_int) ?*Socket; +pub extern fn us_create_child_socket_context(ssl: c_int, context: ?*us_socket_context_t, context_ext_size: c_int) ?*us_socket_context_t; pub const Poll = opaque { pub fn create( diff --git a/src/http/websocket_http_client.zig b/src/http/websocket_http_client.zig index 5e795bb4a..d577fadc6 100644 --- a/src/http/websocket_http_client.zig +++ b/src/http/websocket_http_client.zig @@ -25,8 +25,8 @@ const JSC = @import("javascript_core"); const PicoHTTP = @import("picohttp"); const ObjectPool = @import("../pool.zig").ObjectPool; -fn buildRequestBody(vm: *JSC.VirtualMachine, pathname: *const JSC.ZigString, host: *const JSC.ZigString, client_protocol: *const JSC.ZigString, client_protocol_hash: *u64) ![]u8 { - const allocator = vm.allocator(); +fn buildRequestBody(vm: *JSC.VirtualMachine, pathname: *const JSC.ZigString, host: *const JSC.ZigString, client_protocol: *const JSC.ZigString, client_protocol_hash: *u64) std.mem.Allocator.Error![]u8 { + const allocator = vm.allocator; var input_rand_buf: [16]u8 = undefined; std.crypto.random.bytes(&input_rand_buf); const temp_buf_size = comptime std.base64.standard.Encoder.calcSize(16); @@ -48,23 +48,26 @@ fn buildRequestBody(vm: *JSC.VirtualMachine, pathname: *const JSC.ZigString, hos client_protocol_hash.* = std.hash.Wyhash.hash(0, headers[1].value); var headers_: []PicoHTTP.Header = headers[0 .. 1 + @as(usize, @boolToInt(client_protocol.len > 0))]; - - return try std.fmt.allocPrint(allocator, - \\GET {} HTTP/1.1\r - \\Host: {}\r - \\Pragma: no-cache\r - \\Cache-Control: no-cache\r - \\Connection: Upgrade\r - \\Upgrade: websocket\r - \\Sec-WebSocket-Version: 13\r - \\{s} - \\\r - \\ - , .{ - pathname.*, - host.*, - PicoHTTP.Headers{ .headers = headers_ }, - }); + const pathname_ = pathname.slice(); + const host_ = host.slice(); + const pico_headers = PicoHTTP.Headers{ .headers = headers_ }; + return try std.fmt.allocPrint( + allocator, + "GET {s} HTTP/1.1\r\n" ++ + "Host: {s}\r\n" ++ + "Pragma: no-cache\r\n" ++ + "Cache-Control: no-cache\r\n" ++ + "Connection: Upgrade\r\n" ++ + "Upgrade: websocket\r\n" ++ + "Sec-WebSocket-Version: 13\r\n" ++ + "{any}\n" ++ + "\r\n", + .{ + pathname_, + host_, + pico_headers, + }, + ); } const ErrorCode = enum(i32) { @@ -114,13 +117,13 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { body_written: usize = 0, websocket_protocol: u64 = 0, - const basename = (if (ssl) "SecureWebSocket" else "WebSocket") ++ "UpgradeClient"; + pub const name = if (ssl) "WebSocketHTTPSClient" else "WebSocketHTTPClient"; - pub const shim = JSC.Shimmer("Bun", basename, @This()); + pub const shim = JSC.Shimmer("Bun", name, @This()); const HTTPClient = @This(); - pub fn register(global: *JSC.JSGlobalObject, loop_: *anyopaque, ctx_: *anyopaque) void { + pub fn register(global: *JSC.JSGlobalObject, loop_: *anyopaque, ctx_: *anyopaque) callconv(.C) void { var vm = global.bunVM(); var loop = @ptrCast(*uws.Loop, loop_); var ctx: *uws.us_socket_context_t = @ptrCast(*uws.us_socket_context_t, ctx_); @@ -142,8 +145,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { port: u16, pathname: *const JSC.ZigString, client_protocol: *const JSC.ZigString, - outgoing_usocket: **anyopaque, - ) ?*HTTPClient { + ) callconv(.C) ?*HTTPClient { std.debug.assert(global.bunVM().uws_event_loop != null); var client_protocol_hash: u64 = 0; @@ -158,7 +160,6 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { defer host_.deinit(); if (Socket.connect(host_.slice(), port, @ptrCast(*uws.us_socket_context_t, socket_ctx), HTTPClient, client, "socket")) |out| { - outgoing_usocket.* = out.socket.socket; out.socket.timeout(120); return out; } @@ -179,22 +180,24 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { buf.release(); } } - pub fn cancel(this: *HTTPClient) void { + pub fn cancel(this: *HTTPClient) callconv(.C) void { this.clearData(); if (!this.socket.isEstablished()) { - _ = uws.us_socket_close_connecting(comptime @as(c_int, @boolToInt(ssl)), this.socket); + _ = uws.us_socket_close_connecting(comptime @as(c_int, @boolToInt(ssl)), this.socket.socket); } else { this.socket.close(0, null); } } pub fn fail(this: *HTTPClient, code: ErrorCode) void { + JSC.markBinding(); WebSocket__didFailToConnect(this.outgoing_websocket, code); this.cancel(); } pub fn handleClose(this: *HTTPClient, _: Socket, _: c_int, _: ?*anyopaque) void { + JSC.markBinding(); this.clearData(); WebSocket__didFailToConnect(this.outgoing_websocket, ErrorCode.closed); } @@ -205,7 +208,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { this.socket.close(0, null); } - pub fn handleOpen(this: *HTTPClient, socket: Socket) void { + pub fn handleOpen(this: *HTTPClient, socket: Socket, _: []const u8, _: c_int) void { std.debug.assert(socket.socket == this.socket.socket); std.debug.assert(this.input_body_buf.len > 0); @@ -247,7 +250,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { const to_write = remain[0..@minimum(remain.len, data.len)]; if (data.len > 0 and to_write.len > 0) { - @memcpy(remain.ptr, data, to_write.len); + @memcpy(remain.ptr, data.ptr, to_write.len); this.body_written += to_write.len; } @@ -299,7 +302,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { "Connection".len => { if (connection_header.name.len == 0 and strings.eqlCaseInsensitiveASCII(header.name, "Connection", false)) { connection_header = header; - if (visited_protocol and upgrade_header.len > 0 and connection_header.len > 0 and websocket_accept_header.len > 0 and visited_version) { + if (visited_protocol and upgrade_header.name.len > 0 and connection_header.name.len > 0 and websocket_accept_header.name.len > 0 and visited_version) { break; } } @@ -307,7 +310,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { "Upgrade".len => { if (upgrade_header.name.len == 0 and strings.eqlCaseInsensitiveASCII(header.name, "Upgrade", false)) { upgrade_header = header; - if (visited_protocol and upgrade_header.len > 0 and connection_header.len > 0 and websocket_accept_header.len > 0 and visited_version) { + if (visited_protocol and upgrade_header.name.len > 0 and connection_header.name.len > 0 and websocket_accept_header.name.len > 0 and visited_version) { break; } } @@ -315,7 +318,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { "Sec-WebSocket-Version".len => { if (!visited_version and strings.eqlCaseInsensitiveASCII(header.name, "Sec-WebSocket-Version", false)) { visited_version = true; - if (!strings.eqlComptime(header.value, "13", false)) { + if (!strings.eqlComptimeIgnoreLen(header.value, "13")) { this.terminate(ErrorCode.invalid_websocket_version); return; } @@ -324,7 +327,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { "Sec-WebSocket-Accept".len => { if (websocket_accept_header.name.len == 0 and strings.eqlCaseInsensitiveASCII(header.name, "Sec-WebSocket-Accept", false)) { websocket_accept_header = header; - if (visited_protocol and upgrade_header.len > 0 and connection_header.len > 0 and websocket_accept_header.len > 0 and visited_version) { + if (visited_protocol and upgrade_header.name.len > 0 and connection_header.name.len > 0 and websocket_accept_header.name.len > 0 and visited_version) { break; } } @@ -337,7 +340,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { } visited_protocol = true; - if (visited_protocol and upgrade_header.len > 0 and connection_header.len > 0 and websocket_accept_header.len > 0 and visited_version) { + if (visited_protocol and upgrade_header.name.len > 0 and connection_header.name.len > 0 and websocket_accept_header.name.len > 0 and visited_version) { break; } } @@ -395,6 +398,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { } this.clearData(); + JSC.markBinding(); WebSocket__didConnect(this.outgoing_websocket, this.socket.socket, overflow.ptr, overflow.len); } @@ -425,7 +429,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { this.terminate(ErrorCode.failed_to_connect); } - const Exports = shim.exportFunctions(.{ + pub const Export = shim.exportFunctions(.{ .connect = connect, .cancel = cancel, .register = register, @@ -434,18 +438,18 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type { comptime { if (!JSC.is_bindgen) { @export(connect, .{ - .name = Exports[0].symbol_name, + .name = Export[0].symbol_name, }); @export(cancel, .{ - .name = Exports[1].symbol_name, + .name = Export[1].symbol_name, }); @export(register, .{ - .name = Exports[2].symbol_name, + .name = Export[2].symbol_name, }); } } }; } -pub const WebSocketUpgradeClient = NewHTTPUpgradeClient(false); -pub const SecureWebSocketUpgradeClient = NewHTTPUpgradeClient(true); +pub const WebSocketHTTPClient = NewHTTPUpgradeClient(false); +pub const WebSocketHTTPSClient = NewHTTPUpgradeClient(true); diff --git a/src/javascript/jsc/bindings/JSFFIFunction.h b/src/javascript/jsc/bindings/JSFFIFunction.h index 4d6818db8..e30beb5ea 100644 --- a/src/javascript/jsc/bindings/JSFFIFunction.h +++ b/src/javascript/jsc/bindings/JSFFIFunction.h @@ -10,7 +10,6 @@ class GlobalObject; #include "headers-handwritten.h" #include "BunClientData.h" -#include "WebCoreJSBuiltinInternals.h" #include "JavaScriptCore/CallFrame.h" namespace JSC { diff --git a/src/javascript/jsc/bindings/ScriptExecutionContext.cpp b/src/javascript/jsc/bindings/ScriptExecutionContext.cpp index 17bc266dc..b89e0645f 100644 --- a/src/javascript/jsc/bindings/ScriptExecutionContext.cpp +++ b/src/javascript/jsc/bindings/ScriptExecutionContext.cpp @@ -1,62 +1,129 @@ - +#include "root.h" +#include "headers.h" #include "ScriptExecutionContext.h" + +#include "webcore/WebSocket.h" + #include <uws/src/App.h> -#include "WebSocketStream.h" extern "C" void Bun__startLoop(us_loop_t* loop); namespace WebCore { -template<bool isSSL> -us_socket_context_t* ScriptExecutionContext::webSocketContext() +template<bool SSL, bool isServer> +static void registerHTTPContextForWebSocket(ScriptExecutionContext* script, us_socket_context_t* ctx, us_loop_t* loop) { - if constexpr (isSSL) { - if (!m_ssl_client_websockets_ctx) { - us_loop_t* loop = (us_loop_t*)uWS::Loop::get(); - us_socket_context_options_t opts; - memset(&opts, 0, sizeof(us_socket_context_options_t)); - this->m_ssl_client_websockets_ctx = us_create_socket_context(1, loop, sizeof(size_t), opts); - void** ptr = reinterpret_cast<void**>(us_socket_context_ext(1, m_ssl_client_websockets_ctx)); - *ptr = this; - registerHTTPContextForWebSocket<isSSL, false>(this, m_ssl_client_websockets_ctx); + if constexpr (!isServer) { + if constexpr (SSL) { + Bun__WebSocketHTTPSClient__register(script->jsGlobalObject(), loop, ctx); + } else { + Bun__WebSocketHTTPClient__register(script->jsGlobalObject(), loop, ctx); } - - return m_ssl_client_websockets_ctx; } else { - if (!m_client_websockets_ctx) { - us_loop_t* loop = (us_loop_t*)uWS::Loop::get(); - us_socket_context_options_t opts; - memset(&opts, 0, sizeof(us_socket_context_options_t)); - this->m_client_websockets_ctx = us_create_socket_context(0, loop, sizeof(size_t), opts); - void** ptr = reinterpret_cast<void**>(us_socket_context_ext(0, m_client_websockets_ctx)); - *ptr = this; - registerHTTPContextForWebSocket<isSSL, false>(this, m_client_websockets_ctx); - } + RELEASE_ASSERT_NOT_REACHED(); + } +} - return m_client_websockets_ctx; +us_socket_context_t* ScriptExecutionContext::webSocketContextSSL() +{ + if (!m_ssl_client_websockets_ctx) { + us_loop_t* loop = (us_loop_t*)uWS::Loop::get(); + us_socket_context_options_t opts; + memset(&opts, 0, sizeof(us_socket_context_options_t)); + this->m_ssl_client_websockets_ctx = us_create_socket_context(1, loop, sizeof(size_t), opts); + void** ptr = reinterpret_cast<void**>(us_socket_context_ext(1, m_ssl_client_websockets_ctx)); + *ptr = this; + registerHTTPContextForWebSocket<true, false>(this, m_ssl_client_websockets_ctx, loop); } + + return m_ssl_client_websockets_ctx; } -template<bool isSSL, bool isServer> -uWS::WebSocketContext<isSSL, isServer, ScriptExecutionContext*>* ScriptExecutionContext::connnectedWebSocketContext() +us_socket_context_t* ScriptExecutionContext::webSocketContextNoSSL() { - if constexpr (isSSL) { - if (!m_connected_ssl_client_websockets_ctx) { - // should be the parent - RELEASE_ASSERT(m_ssl_client_websockets_ctx); - m_connected_client_websockets_ctx = registerWebSocketClientContext(this, webSocketContext<isSSL>()); - } + if (!m_client_websockets_ctx) { + us_loop_t* loop = (us_loop_t*)uWS::Loop::get(); + us_socket_context_options_t opts; + memset(&opts, 0, sizeof(us_socket_context_options_t)); + this->m_client_websockets_ctx = us_create_socket_context(0, loop, sizeof(size_t), opts); + void** ptr = reinterpret_cast<void**>(us_socket_context_ext(0, m_client_websockets_ctx)); + *ptr = this; + registerHTTPContextForWebSocket<false, false>(this, m_client_websockets_ctx, loop); + } - return m_connected_ssl_client_websockets_ctx; - } else { - if (!m_connected_client_websockets_ctx) { - // should be the parent - RELEASE_ASSERT(m_client_websockets_ctx); - m_connected_client_websockets_ctx = registerWebSocketClientContext(this, webSocketContext<isSSL>()); + return m_client_websockets_ctx; +} + +template<bool SSL> +static uWS::WebSocketContext<SSL, false, WebCore::WebSocket*>* registerWebSocketClientContext(ScriptExecutionContext* script, us_socket_context_t* parent) +{ + uWS::Loop* loop = uWS::Loop::get(); + uWS::WebSocketContext<SSL, false, WebCore::WebSocket*>* ctx = uWS::WebSocketContext<SSL, false, WebCore::WebSocket*>::createClient(loop, parent); + + auto* opts = ctx->getExt(); + + /* Maximum message size we can receive */ + static unsigned int maxPayloadLength = 128 * 1024 * 1024; + /* 2 minutes timeout is good */ + static unsigned short idleTimeout = 120; + /* 64kb backpressure is probably good */ + static unsigned int maxBackpressure = 128 * 1024 * 1024; + static bool closeOnBackpressureLimit = false; + /* This one depends on kernel timeouts and is a bad default */ + static bool resetIdleTimeoutOnSend = false; + /* A good default, esp. for newcomers */ + static bool sendPingsAutomatically = true; + /* Maximum socket lifetime in seconds before forced closure (defaults to disabled) */ + static unsigned short maxLifetime = 0; + + opts->maxPayloadLength = maxPayloadLength; + opts->maxBackpressure = maxBackpressure; + opts->closeOnBackpressureLimit = closeOnBackpressureLimit; + opts->resetIdleTimeoutOnSend = resetIdleTimeoutOnSend; + opts->sendPingsAutomatically = sendPingsAutomatically; + // opts->compression = compression; + // TODO: + opts->compression = uWS::CompressOptions::DISABLED; + + opts->openHandler = [](uWS::WebSocket<SSL, false, WebCore::WebSocket*>* ws) { + WebCore::WebSocket* webSocket = *ws->getUserData(); + webSocket->didConnect(); + }; + + opts->messageHandler = [](uWS::WebSocket<SSL, false, WebCore::WebSocket*>* ws, std::string_view input, uWS::OpCode opCode) { + WebCore::WebSocket* webSocket = *ws->getUserData(); + if (opCode == uWS::OpCode::BINARY) { + webSocket->didReceiveBinaryData({ const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(input.data())), input.length() }); + } else { + webSocket->didReceiveMessage(WTF::String::fromUTF8(input.data(), input.length())); } + }; - return m_connected_client_websockets_ctx; - } + // pts->drainHandler = [](uWS::WebSocket<SSL, false, WebCore::WebSocket>* ws, std::string_view input, uWS::OpCode opCode) { + // WebCore::WebSocket* webSocket = *ws->getUserData(); + // webSocket->didReceiveData(input.data(), input.length()); + // }; + + opts->closeHandler = [](uWS::WebSocket<SSL, false, WebCore::WebSocket*>* ws, int code, std::string_view message) { + WebCore::WebSocket* webSocket = *ws->getUserData(); + webSocket->didClose( + ws->getBufferedAmount(), + code, + WTF::String::fromUTF8( + message.data(), + message.length())); + }; + + return ctx; +} + +uWS::WebSocketContext<false, false, WebSocket*>* ScriptExecutionContext::connectedWebSocketKindClient() +{ + return registerWebSocketClientContext<false>(this, webSocketContextNoSSL()); +} +uWS::WebSocketContext<true, false, WebSocket*>* ScriptExecutionContext::connectedWebSocketKindClientSSL() +{ + return registerWebSocketClientContext<true>(this, webSocketContextSSL()); } }
\ No newline at end of file diff --git a/src/javascript/jsc/bindings/ScriptExecutionContext.h b/src/javascript/jsc/bindings/ScriptExecutionContext.h index f966cf5f6..ea8302356 100644 --- a/src/javascript/jsc/bindings/ScriptExecutionContext.h +++ b/src/javascript/jsc/bindings/ScriptExecutionContext.h @@ -14,20 +14,18 @@ namespace uWS { template<bool isServer, bool isClient, typename UserData> struct WebSocketContext; + } struct us_socket_t; struct us_socket_context_t; +struct us_loop_t; namespace WebCore { -class ScriptExecutionContext : public CanMakeWeakPtr<ScriptExecutionContext> { +class WebSocket; +class ScriptExecutionContext : public CanMakeWeakPtr<ScriptExecutionContext> { public: - ScriptExecutionContext(JSC::VM* vm, JSC::JSGlobalObject* globalObject) - : m_vm(vm) - , m_globalObject(globalObject) - { - } class Task { WTF_MAKE_FAST_ALLOCATED; @@ -62,16 +60,27 @@ public: bool m_isCleanupTask; }; +public: + ScriptExecutionContext(JSC::VM* vm, JSC::JSGlobalObject* globalObject) + : m_vm(vm) + , m_globalObject(globalObject) + { + } + JSC::JSGlobalObject* jsGlobalObject() { return m_globalObject; } template<bool isSSL> - us_socket_context_t* webSocketContext(); - - template<bool isSSL, bool isServer> - uWS::WebSocketContext<isSSL, isServer, ScriptExecutionContext*>* connnectedWebSocketContext(); + us_socket_context_t* webSocketContext() + { + if constexpr (isSSL) { + return this->webSocketContextSSL(); + } else { + return this->webSocketContextNoSSL(); + } + } const WTF::URL& url() const { return m_url; } bool activeDOMObjectsAreSuspended() { return false; } @@ -107,10 +116,34 @@ private: JSC::JSGlobalObject* m_globalObject = nullptr; WTF::URL m_url = WTF::URL(); + us_socket_context_t* webSocketContextSSL(); + us_socket_context_t* webSocketContextNoSSL(); + uWS::WebSocketContext<true, false, WebSocket*>* connectedWebSocketKindClientSSL(); + uWS::WebSocketContext<false, false, WebSocket*>* connectedWebSocketKindClient(); + us_socket_context_t* m_ssl_client_websockets_ctx = nullptr; us_socket_context_t* m_client_websockets_ctx = nullptr; - uWS::WebSocketContext<true, false, ScriptExecutionContext*>* m_connected_ssl_client_websockets_ctx = nullptr; - uWS::WebSocketContext<true, true, ScriptExecutionContext*>* m_connected_client_websockets_ctx = nullptr; + uWS::WebSocketContext<true, false, WebSocket*>* m_connected_ssl_client_websockets_ctx = nullptr; + uWS::WebSocketContext<false, false, WebSocket*>* m_connected_client_websockets_ctx = nullptr; + +public: + template<bool isSSL, bool isServer> + uWS::WebSocketContext<isSSL, isServer, WebSocket*>* connnectedWebSocketContext() + { + if constexpr (isSSL) { + if (!m_connected_ssl_client_websockets_ctx) { + m_connected_ssl_client_websockets_ctx = connectedWebSocketKindClientSSL(); + } + + return m_connected_ssl_client_websockets_ctx; + } else { + if (!m_connected_client_websockets_ctx) { + m_connected_client_websockets_ctx = connectedWebSocketKindClient(); + } + + return m_connected_client_websockets_ctx; + } + } }; }
\ No newline at end of file diff --git a/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h b/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h index c52f65d85..d533abeec 100644 --- a/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h +++ b/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h @@ -1,5 +1,7 @@ //clang-format off -namespace Zig { class GlobalObject; } +namespace Zig { +class GlobalObject; +} /* * Copyright (c) 2015 Igalia * Copyright (c) 2015 Igalia S.L. @@ -8,7 +10,7 @@ namespace Zig { 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: @@ -17,7 +19,7 @@ namespace Zig { 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 @@ -29,7 +31,7 @@ namespace Zig { 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/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index 6890c045b..53872f325 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -1,4 +1,5 @@ +#include "root.h" #include "ZigGlobalObject.h" #include "helpers.h" @@ -135,6 +136,8 @@ using JSBuffer = WebCore::JSBuffer; #include "JavaScriptCore/BuiltinNames.h" #include "JSTextEncoder.h" #include "StructuredClone.h" +#include "JSWebSocket.h" +#include "JSMessageEvent.h" #include "ReadableStream.h" #include "JSSink.h" @@ -453,6 +456,28 @@ JSC_DEFINE_CUSTOM_GETTER(JSCloseEvent_getter, WebCore::JSCloseEvent::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); } +JSC_DECLARE_CUSTOM_GETTER(JSMessageEvent_getter); + +JSC_DEFINE_CUSTOM_GETTER(JSMessageEvent_getter, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::PropertyName)) +{ + Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); + return JSC::JSValue::encode( + WebCore::JSMessageEvent::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); +} + +JSC_DECLARE_CUSTOM_GETTER(JSWebSocket_getter); + +JSC_DEFINE_CUSTOM_GETTER(JSWebSocket_getter, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::PropertyName)) +{ + Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); + return JSC::JSValue::encode( + WebCore::JSWebSocket::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); +} + JSC_DECLARE_CUSTOM_GETTER(JSEvent_getter); JSC_DEFINE_CUSTOM_GETTER(JSEvent_getter, @@ -1872,6 +1897,12 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CloseEvent"_s), JSC::CustomGetterSetter::create(vm, JSCloseEvent_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "MessageEvent"_s), JSC::CustomGetterSetter::create(vm, JSMessageEvent_getter, nullptr), + JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "WebSocket"_s), JSC::CustomGetterSetter::create(vm, JSWebSocket_getter, nullptr), + JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Buffer"_s), JSC::CustomGetterSetter::create(vm, JSBuffer_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "TextEncoder"_s), JSC::CustomGetterSetter::create(vm, JSTextEncoder_getter, nullptr), diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig index 04142d040..0c9c2a677 100644 --- a/src/javascript/jsc/bindings/exports.zig +++ b/src/javascript/jsc/bindings/exports.zig @@ -186,6 +186,10 @@ pub const JSReadableStreamFile = JSC.WebCore.FileBlobLoader.Source.JSReadableStr // Sinks pub const JSArrayBufferSink = JSC.WebCore.ArrayBufferSink.JSSink; +// WebSocket +pub const WebSocketHTTPClient = @import("../../../http/websocket_http_client.zig").WebSocketHTTPClient; +pub const WebSocketHTTSPClient = @import("../../../http/websocket_http_client.zig").WebSocketHTTPSClient; + pub fn Errorable(comptime Type: type) type { return extern struct { result: Result, @@ -2504,6 +2508,9 @@ pub const BunTimer = Bun.Timer; pub const Formatter = ZigConsoleClient.Formatter; comptime { + WebSocketHTTPClient.shim.ref(); + WebSocketHTTSPClient.shim.ref(); + if (!is_bindgen) { _ = Process.getTitle; _ = Process.setTitle; diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h index 09731ce13..8d44b538a 100644 --- a/src/javascript/jsc/bindings/headers-cpp.h +++ b/src/javascript/jsc/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1655351052 +//-- AUTOGENERATED FILE -- 1655526456 // clang-format off #pragma once diff --git a/src/javascript/jsc/bindings/headers-handwritten.h b/src/javascript/jsc/bindings/headers-handwritten.h index a2f15cb74..995393b93 100644 --- a/src/javascript/jsc/bindings/headers-handwritten.h +++ b/src/javascript/jsc/bindings/headers-handwritten.h @@ -187,6 +187,9 @@ typedef struct StringPointer { } StringPointer; #endif +typedef void WebSocketHTTPClient; +typedef void WebSocketHTTPSClient; + #ifdef __cplusplus extern "C" ZigErrorCode Zig_ErrorCodeParserError; diff --git a/src/javascript/jsc/bindings/headers-replacements.zig b/src/javascript/jsc/bindings/headers-replacements.zig index 4491c79af..80f3dd6dc 100644 --- a/src/javascript/jsc/bindings/headers-replacements.zig +++ b/src/javascript/jsc/bindings/headers-replacements.zig @@ -65,3 +65,6 @@ pub const struct_WebCore__FetchHeaders = bindings.FetchHeaders; pub const StringPointer = @import("../../../api/schema.zig").Api.StringPointer; pub const struct_VirtualMachine = bindings.VirtualMachine; pub const ArrayBufferSink = @import("../webcore/streams.zig").ArrayBufferSink; + +pub const WebSocketHTTPClient = bindings.WebSocketHTTPClient; +pub const WebSocketHTTPSClient = bindings.WebSocketHTTPSClient; diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index 0257c39ed..0a23cdd2c 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format: off -//-- AUTOGENERATED FILE -- 1655351052 +//-- AUTOGENERATED FILE -- 1655526456 #pragma once #include <stddef.h> @@ -137,6 +137,7 @@ typedef bJSC__Identifier JSC__Identifier; // JSC::Identifier typedef struct JSC__ArrayPrototype JSC__ArrayPrototype; // JSC::ArrayPrototype typedef struct Zig__JSMicrotaskCallback Zig__JSMicrotaskCallback; // Zig::JSMicrotaskCallback typedef bJSC__JSPromise JSC__JSPromise; // JSC::JSPromise +typedef WebSocketHTTPClient WebSocketHTTPClient; typedef struct JSC__SetIteratorPrototype JSC__SetIteratorPrototype; // JSC::SetIteratorPrototype typedef SystemError SystemError; typedef bJSC__JSCell JSC__JSCell; // JSC::JSCell @@ -155,6 +156,7 @@ 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 +typedef WebSocketHTTPSClient WebSocketHTTPSClient; typedef bJSC__VM JSC__VM; // JSC::VM typedef JSClassRef JSClassRef; typedef Bun__ArrayBuffer Bun__ArrayBuffer; @@ -235,9 +237,11 @@ class ScriptArguments; typedef ErrorableResolvedSource ErrorableResolvedSource; typedef ErrorableZigString ErrorableZigString; +typedef WebSocketHTTPClient WebSocketHTTPClient; typedef SystemError SystemError; typedef Bun__Writable Bun__Writable; typedef Bun__Readable Bun__Readable; +typedef WebSocketHTTPSClient WebSocketHTTPSClient; typedef JSClassRef JSClassRef; typedef Bun__ArrayBuffer Bun__ArrayBuffer; typedef ZigException ZigException; @@ -792,6 +796,22 @@ ZIG_DECL JSC__JSValue ArrayBufferSink__write(JSC__JSGlobalObject* arg0, JSC__Cal #ifdef __cplusplus +ZIG_DECL void Bun__WebSocketHTTPClient__cancel(WebSocketHTTPClient* arg0); +ZIG_DECL WebSocketHTTPClient* Bun__WebSocketHTTPClient__connect(JSC__JSGlobalObject* arg0, void* arg1, void* arg2, const ZigString* arg3, uint16_t arg4, const ZigString* arg5, const ZigString* arg6); +ZIG_DECL void Bun__WebSocketHTTPClient__register(JSC__JSGlobalObject* arg0, void* arg1, void* arg2); + +#endif + +#ifdef __cplusplus + +ZIG_DECL void Bun__WebSocketHTTPSClient__cancel(WebSocketHTTPSClient* arg0); +ZIG_DECL WebSocketHTTPSClient* Bun__WebSocketHTTPSClient__connect(JSC__JSGlobalObject* arg0, void* arg1, void* arg2, const ZigString* arg3, uint16_t arg4, const ZigString* arg5, const ZigString* arg6); +ZIG_DECL void Bun__WebSocketHTTPSClient__register(JSC__JSGlobalObject* arg0, void* arg1, void* arg2); + +#endif + +#ifdef __cplusplus + ZIG_DECL void Bun__Process__exit(JSC__JSGlobalObject* arg0, int32_t arg1); ZIG_DECL JSC__JSValue Bun__Process__getArgv(JSC__JSGlobalObject* arg0); ZIG_DECL JSC__JSValue Bun__Process__getCwd(JSC__JSGlobalObject* arg0); diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index ee59be0a4..4b05ed250 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -65,6 +65,9 @@ pub const struct_WebCore__FetchHeaders = bindings.FetchHeaders; pub const StringPointer = @import("../../../api/schema.zig").Api.StringPointer; pub const struct_VirtualMachine = bindings.VirtualMachine; pub const ArrayBufferSink = @import("../webcore/streams.zig").ArrayBufferSink; + +pub const WebSocketHTTPClient = bindings.WebSocketHTTPClient; +pub const WebSocketHTTPSClient = bindings.WebSocketHTTPSClient; // GENERATED CODE - DO NOT MODIFY BY HAND pub const ptrdiff_t = c_long; @@ -261,7 +264,6 @@ pub extern fn JSC__JSGlobalObject__putCachedObject(arg0: [*c]JSC__JSGlobalObject pub extern fn JSC__JSGlobalObject__regExpPrototype(arg0: [*c]JSC__JSGlobalObject) ?*JSC__RegExpPrototype; pub extern fn JSC__JSGlobalObject__setIteratorPrototype(arg0: [*c]JSC__JSGlobalObject) ?*JSC__SetIteratorPrototype; pub extern fn JSC__JSGlobalObject__startRemoteInspector(arg0: [*c]JSC__JSGlobalObject, arg1: [*c]u8, arg2: u16) bool; -pub extern fn JSC__JSGlobalObject__stopRemoteInspector(arg0: [*c]JSC__JSGlobalObject) void; pub extern fn JSC__JSGlobalObject__stringPrototype(arg0: [*c]JSC__JSGlobalObject) ?*JSC__StringPrototype; pub extern fn JSC__JSGlobalObject__symbolPrototype(arg0: [*c]JSC__JSGlobalObject) [*c]JSC__JSObject; pub extern fn JSC__JSGlobalObject__vm(arg0: [*c]JSC__JSGlobalObject) [*c]JSC__VM; diff --git a/src/javascript/jsc/bindings/napi.h b/src/javascript/jsc/bindings/napi.h index 4a9743d6e..754c34ec4 100644 --- a/src/javascript/jsc/bindings/napi.h +++ b/src/javascript/jsc/bindings/napi.h @@ -10,7 +10,6 @@ class GlobalObject; #include "headers-handwritten.h" #include "BunClientData.h" -#include "WebCoreJSBuiltinInternals.h" #include "JavaScriptCore/CallFrame.h" #include "js_native_api_types.h" #include "JavaScriptCore/JSWeakValue.h" diff --git a/src/javascript/jsc/bindings/sqlite/JSSQLStatement.h b/src/javascript/jsc/bindings/sqlite/JSSQLStatement.h index 51e8fba99..6bf830ee2 100644 --- a/src/javascript/jsc/bindings/sqlite/JSSQLStatement.h +++ b/src/javascript/jsc/bindings/sqlite/JSSQLStatement.h @@ -33,7 +33,6 @@ #include "headers-handwritten.h" #include "BunClientData.h" -#include "WebCoreJSBuiltinInternals.h" #include "JavaScriptCore/CallFrame.h" #if defined(__APPLE__) diff --git a/src/javascript/jsc/bindings/webcore/EventFactory.cpp b/src/javascript/jsc/bindings/webcore/EventFactory.cpp index 0c431eb9f..3677b9dfe 100644 --- a/src/javascript/jsc/bindings/webcore/EventFactory.cpp +++ b/src/javascript/jsc/bindings/webcore/EventFactory.cpp @@ -156,8 +156,8 @@ JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObj // case MerchantValidationEventInterfaceType: // return createWrapper<MerchantValidationEvent>(globalObject, WTFMove(impl)); // #endif - // case MessageEventInterfaceType: - // return createWrapper<MessageEvent>(globalObject, WTFMove(impl)); + case MessageEventInterfaceType: + return createWrapper<MessageEvent>(globalObject, WTFMove(impl)); // case MouseEventInterfaceType: // return createWrapper<MouseEvent>(globalObject, WTFMove(impl)); // case MutationEventInterfaceType: diff --git a/src/javascript/jsc/bindings/webcore/EventHeaders.h b/src/javascript/jsc/bindings/webcore/EventHeaders.h index 3937c5c2b..347d333d0 100644 --- a/src/javascript/jsc/bindings/webcore/EventHeaders.h +++ b/src/javascript/jsc/bindings/webcore/EventHeaders.h @@ -146,8 +146,8 @@ // #include "MerchantValidationEvent.h" // #include "JSMerchantValidationEvent.h" // #endif -// #include "MessageEvent.h" -// #include "JSMessageEvent.h" +#include "MessageEvent.h" +#include "JSMessageEvent.h" // #include "MouseEvent.h" // #include "JSMouseEvent.h" // #include "MutationEvent.h" diff --git a/src/javascript/jsc/bindings/webcore/JSMessageEvent.cpp b/src/javascript/jsc/bindings/webcore/JSMessageEvent.cpp index 4b951a5a6..ef0a1093d 100644 --- a/src/javascript/jsc/bindings/webcore/JSMessageEvent.cpp +++ b/src/javascript/jsc/bindings/webcore/JSMessageEvent.cpp @@ -419,9 +419,10 @@ static inline JSC::EncodedJSValue jsMessageEventPrototypeFunction_initMessageEve // RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); // EnsureStillAliveScope argument7 = callFrame->argument(7); // auto messagePorts = JSArray::create(lexicalGlobalObject.vm(), lexicalGlobalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0); - auto messagePorts = Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {}; + // auto messagePorts = Converter<IDLSequence<IDLInterface<MessagePort>>>::ReturnType {}; RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); - RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.initMessageEvent(WTFMove(type), WTFMove(bubbles), WTFMove(cancelable), WTFMove(data), WTFMove(originArg), WTFMove(lastEventId), WTFMove(source), WTFMove(messagePorts)); }))); + // RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.initMessageEvent(WTFMove(type), WTFMove(bubbles), WTFMove(cancelable), WTFMove(data), WTFMove(originArg), WTFMove(lastEventId), WTFMove(source), WTFMove(messagePorts)); }))); + RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.initMessageEvent(WTFMove(type), WTFMove(bubbles), WTFMove(cancelable), WTFMove(data), WTFMove(originArg), WTFMove(lastEventId), WTFMove(source)); }))); } JSC_DEFINE_HOST_FUNCTION(jsMessageEventPrototypeFunction_initMessageEvent, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) diff --git a/src/javascript/jsc/bindings/webcore/WebSocket.cpp b/src/javascript/jsc/bindings/webcore/WebSocket.cpp index dff4500be..691da6aae 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocket.cpp +++ b/src/javascript/jsc/bindings/webcore/WebSocket.cpp @@ -31,7 +31,8 @@ #include "config.h" #include "WebSocket.h" - +#include "WebSocketStream.h" +#include "headers.h" // #include "Blob.h" #include "CloseEvent.h" // #include "ContentSecurityPolicy.h" @@ -75,9 +76,6 @@ // #include "WebCoreThreadRun.h" // #endif namespace WebCore { -using WebSocketChannel = WebSocketStream; -using ThreadableWebSocketChannel = WebSocketStream; -using WebSocketChannelClient = WebSocketStream; WTF_MAKE_ISO_ALLOCATED_IMPL(WebSocket); static size_t getFramingOverhead(size_t payloadSize) @@ -170,9 +168,9 @@ WebSocket::~WebSocket() if (m_upgradeClient != nullptr) { void* upgradeClient = m_upgradeClient; if (m_isSecure) { - Bun_SecureWebSocketUpgradeClient__cancel(upgradeClient); + Bun__WebSocketHTTPSClient__cancel(upgradeClient); } else { - Bun_WebSocketUpgradeClient__cancel(upgradeClient); + Bun__WebSocketHTTPClient__cancel(upgradeClient); } } @@ -374,11 +372,11 @@ ExceptionOr<void> WebSocket::connect(const String& url, const Vector<String>& pr if (is_secure) { us_socket_context_t* ctx = scriptExecutionContext()->webSocketContext<true>(); RELEASE_ASSERT(ctx); - this->m_upgradeClient = Bun_SecureWebSocketUpgradeClient__connect(scriptExecutionContext()->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); + this->m_upgradeClient = Bun__WebSocketHTTPSClient__connect(scriptExecutionContext()->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); } else { us_socket_context_t* ctx = scriptExecutionContext()->webSocketContext<false>(); RELEASE_ASSERT(ctx); - this->m_upgradeClient = Bun_WebSocketUpgradeClient__connect(scriptExecutionContext()->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); + this->m_upgradeClient = Bun__WebSocketHTTPClient__connect(scriptExecutionContext()->jsGlobalObject(), ctx, this, &host, port, &path, &clientProtocolString); } if (this->m_upgradeClient == nullptr) { @@ -455,7 +453,6 @@ ExceptionOr<void> WebSocket::send(ArrayBufferView& arrayBufferView) m_bufferedAmountAfterClose = saturateAdd(m_bufferedAmountAfterClose, getFramingOverhead(payloadSize)); return {}; } - ASSERT(m_channel); auto buffer = arrayBufferView.unsharedBuffer().get(); char* baseAddress = reinterpret_cast<char*>(buffer->data()) + arrayBufferView.byteOffset(); @@ -522,8 +519,8 @@ ExceptionOr<void> WebSocket::close(std::optional<unsigned short> optionalCode, c { CString utf8 = reason.utf8(StrictConversionReplacingUnpairedSurrogatesWithFFFD); - int code = optionalCode ? optionalCode.value() : static_cast<int>(WebSocketChannel::CloseEventCodeNotSpecified); - if (code == WebSocketChannel::CloseEventCodeNotSpecified) + int code = optionalCode ? optionalCode.value() : static_cast<int>(0); + if (code == 0) LOG(Network, "WebSocket %p close() without code and reason", this); else { LOG(Network, "WebSocket %p close() code=%d reason='%s'", this, code, reason.utf8().data()); @@ -543,9 +540,9 @@ ExceptionOr<void> WebSocket::close(std::optional<unsigned short> optionalCode, c void* upgradeClient = m_upgradeClient; m_upgradeClient = nullptr; if (m_isSecure) { - Bun_SecureWebSocketUpgradeClient__cancel(upgradeClient); + Bun__WebSocketHTTPSClient__cancel(upgradeClient); } else { - Bun_WebSocketUpgradeClient__cancel(upgradeClient); + Bun__WebSocketHTTPClient__cancel(upgradeClient); } } return {}; @@ -581,11 +578,6 @@ ExceptionOr<void> WebSocket::close(std::optional<unsigned short> optionalCode, c return {}; } -WebSocketChannelClient* WebSocket::channel() const -{ - return m_channel; -} - const URL& WebSocket::url() const { return m_url; @@ -697,7 +689,7 @@ void WebSocket::didConnect() if (m_state == CLOSED) return; if (m_state != CONNECTING) { - didClose(0, ClosingHandshakeIncomplete, WebSocketChannel::CloseEventCodeAbnormalClosure, emptyString()); + didClose(0, 0, emptyString()); return; } ASSERT(scriptExecutionContext()); @@ -787,7 +779,7 @@ void WebSocket::didStartClosingHandshake() // }); } -void WebSocket::didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason) +void WebSocket::didClose(unsigned unhandledBufferedAmount, unsigned short code, const String& reason) { LOG(Network, "WebSocket %p didClose()", this); if (this->m_connectedWebSocketKind == ConnectedWebSocketKind::None) @@ -805,7 +797,7 @@ void WebSocket::didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompl // } // } - bool wasClean = m_state == CLOSING && !unhandledBufferedAmount && closingHandshakeCompletion == ClosingHandshakeComplete && code != WebSocketChannel::CloseEventCodeAbnormalClosure; + bool wasClean = m_state == CLOSING && !unhandledBufferedAmount && code != 0; // WebSocketChannel::CloseEventCodeAbnormalClosure; m_state = CLOSED; m_bufferedAmount = unhandledBufferedAmount; ASSERT(scriptExecutionContext()); diff --git a/src/javascript/jsc/bindings/webcore/WebSocket.h b/src/javascript/jsc/bindings/webcore/WebSocket.h index b75bc346c..351e8c6b6 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocket.h +++ b/src/javascript/jsc/bindings/webcore/WebSocket.h @@ -37,7 +37,10 @@ #include <wtf/HashSet.h> #include <wtf/Lock.h> -#include "WebSocketStream.h" +namespace uWS { +template<bool, bool, typename> +struct WebSocket; +} namespace JSC { class ArrayBuffer; @@ -49,14 +52,6 @@ namespace WebCore { // class Blob; class WebSocket final : public RefCounted<WebSocket>, public EventTargetWithInlineData, public ContextDestructionObserver { WTF_MAKE_ISO_ALLOCATED(WebSocket); - friend struct uWS::WebSocket<false, false, WebSocket*>; - friend struct uWS::WebSocket<false, true, WebSocket*>; - friend struct uWS::WebSocket<true, false, WebSocket*>; - friend struct uWS::WebSocket<true, true, WebSocket*>; - friend WebCore::WebSocketStream; - friend WebCore::SecureWebSocketStream; - friend WebCore::ServerWebSocketStream; - friend WebCore::ServerSecureWebSocketStream; public: static ASCIILiteral subprotocolSeparator(); @@ -85,8 +80,6 @@ public: ExceptionOr<void> close(std::optional<unsigned short> code, const String& reason); - WebSocketStream* channel() const; - const URL& url() const; State readyState() const; unsigned bufferedAmount() const; @@ -102,16 +95,20 @@ public: using RefCounted::deref; using RefCounted::ref; void didConnect(); - void didClose(unsigned unhandledBufferedAmount, ClosingHandshakeCompletionStatus, unsigned short code, const String& reason); + void didClose(unsigned unhandledBufferedAmount, unsigned short code, const String& reason); void didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize); void didFailToConnect(int32_t code); + void didReceiveMessage(String&& message); + void didReceiveData(const char* data, size_t length); + void didReceiveBinaryData(Vector<uint8_t>&&); + private: typedef union AnyWebSocket { - uWS::WebSocket<false, false, WebSocket*>* client; - uWS::WebSocket<true, false, WebSocket*>* clientSSL; - uWS::WebSocket<false, true, WebSocket*>* server; - uWS::WebSocket<true, true, WebSocket*>* serverSSL; + uWS::WebSocket<false, false, WebCore::WebSocket*>* client; + uWS::WebSocket<true, false, WebCore::WebSocket*>* clientSSL; + uWS::WebSocket<false, true, WebCore::WebSocket*>* server; + uWS::WebSocket<true, true, WebCore::WebSocket*>* serverSSL; } AnyWebSocket; enum ConnectedWebSocketKind { None, @@ -137,9 +134,6 @@ private: void refEventTarget() final { ref(); } void derefEventTarget() final { deref(); } - void didReceiveMessage(String&& message); - void didReceiveData(const char* data, size_t length); - void didReceiveBinaryData(Vector<uint8_t>&&); void didReceiveMessageError(WTF::StringImpl::StaticStringImpl* reason); void didUpdateBufferedAmount(unsigned bufferedAmount); void didStartClosingHandshake(); @@ -152,8 +146,6 @@ private: enum class BinaryType { Blob, ArrayBuffer }; - WebSocketStream* m_channel { nullptr }; - State m_state { CONNECTING }; URL m_url; unsigned m_bufferedAmount { 0 }; diff --git a/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp b/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp index 9aa480bbe..c318130b8 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp +++ b/src/javascript/jsc/bindings/webcore/WebSocketStream.cpp @@ -1,88 +1,10 @@ #include "root.h" +#include "headers.h" #include "WebSocketStream.h" #include "ScriptExecutionContext.h" #include <uws/src/App.h> #include <uws/uSockets/src/libusockets.h> - namespace WebCore { -template<bool SSL, bool isServer> -void registerHTTPContextForWebSocket(ScriptExecutionContext* script, us_socket_context_t* ctx, us_loop_t* loop) -{ - if constexpr (!isServer) { - if constexpr (SSL) { - Bun__SecureWebSocketUpgradeClient__register(script->jsGlobalObject(), loop, ctx); - } else { - Bun__WebSocketUpgradeClient__register(script->jsGlobalObject(), loop, ctx); - } - } else { - RELEASE_ASSERT_NOT_REACHED(); - } -} - -template<bool SSL, bool isServer> -uWS::WebSocketContext<SSL, isServer, ScriptExecutionContext*>* registerWebSocketClientContext(ScriptExecutionContext* script, us_socket_context_t* parent) -{ - uWS::Loop* loop = uWS::Loop::get(); - uWS::WebSocketContext<SSL, isServer, ScriptExecutionContext*>* ctx = uWS::WebSocketContext<SSL, isServer>::create(loop, parent, nullptr); - auto* opts = ctx->getExt(); - ScriptExecutionContext** scriptCtx = ctx->getUserData(); - *scriptCtx = script; - - /* Maximum message size we can receive */ - static unsigned int maxPayloadLength = 128 * 1024 * 1024; - /* 2 minutes timeout is good */ - static unsigned short idleTimeout = 120; - /* 64kb backpressure is probably good */ - static unsigned int maxBackpressure = 128 * 1024 * 1024; - static bool closeOnBackpressureLimit = false; - /* This one depends on kernel timeouts and is a bad default */ - static bool resetIdleTimeoutOnSend = false; - /* A good default, esp. for newcomers */ - static bool sendPingsAutomatically = true; - /* Maximum socket lifetime in seconds before forced closure (defaults to disabled) */ - static unsigned short maxLifetime = 0; - - opts->maxPayloadLength = maxPayloadLength; - opts->maxBackpressure = maxBackpressure; - opts->closeOnBackpressureLimit = closeOnBackpressureLimit; - opts->resetIdleTimeoutOnSend = resetIdleTimeoutOnSend; - opts->sendPingsAutomatically = sendPingsAutomatically; - // opts->compression = compression; - // TODO: - opts->compression = false; - - opts->openHandler = [](uWS::WebSocket<SSL, isServer, WebCore::WebSocket>* ws) { - auto* webSocket = ws->getUserData(); - webSocket->didOpen(); - }; - - opts->messageHandler = [](uWS::WebSocket<SSL, isServer, WebCore::WebSocket>* ws, std::string_view input, uWS::OpCode opCode) { - auto* webSocket = ws->getUserData(); - if (opCode == uWS::OpCode::BINARY) { - webSocket->didReceiveBinaryData({ input.data(), input.length() }); - } else { - webSocket->didReceiveMessage(WTF::String::fromUTF8(input.data(), input.length())); - } - }; - - // pts->drainHandler = [](uWS::WebSocket<SSL, isServer, WebCore::WebSocket>* ws, std::string_view input, uWS::OpCode opCode) { - // auto* webSocket = ws->getUserData(); - // webSocket->didReceiveData(input.data(), input.length()); - // }; - - opts->closeHandler = [](uWS::WebSocket<SSL, isServer, WebCore::WebSocket>* ws, int code, std::string_view message) { - auto* webSocket = ws->getUserData(); - webSocket->didClose( - ws->getBufferedAmount(), - code, - WTF::String::fromUTF8( - message.data(), - message.length())); - }; - - return ctx; -} - }
\ No newline at end of file diff --git a/src/javascript/jsc/bindings/webcore/WebSocketStream.h b/src/javascript/jsc/bindings/webcore/WebSocketStream.h index b6a2595a3..78c142864 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocketStream.h +++ b/src/javascript/jsc/bindings/webcore/WebSocketStream.h @@ -29,6 +29,7 @@ */ #pragma once +#include "root.h" #include "wtf/text/StringImpl.h" #include "wtf/text/StringView.h" @@ -36,6 +37,8 @@ #include "wtf/URL.h" #include "wtf/Vector.h" #include "wtf/Function.h" +#include "ScriptExecutionContext.h" +#include "headers.h" namespace uWS { template<bool, bool, typename> @@ -111,15 +114,4 @@ public: } }; -template<bool isSSL, bool isServer> -void registerHTTPContextForWebSocket(ScriptExecutionContext*, us_socket_context_t*); - -template<bool SSL, bool isServer> -uWS::WebSocketContext<SSL, isServer, ScriptExecutionContext*>* registerWebSocketClientContext(ScriptExecutionContext*, us_socket_context_t* parent); - -using WebSocketStream = WebSocketStreamBase<false, false>; -using SecureWebSocketStream = WebSocketStreamBase<true, false>; -using ServerWebSocketStream = WebSocketStreamBase<false, true>; -using ServerSecureWebSocketStream = WebSocketStreamBase<true, true>; - } // namespace WebCore |