diff options
author | 2023-01-09 03:25:06 -0800 | |
---|---|---|
committer | 2023-01-09 03:25:06 -0800 | |
commit | ced6201cb0433c11d8b7ca9e60de61b133cc8fab (patch) | |
tree | 008c125e683009824b2a5cd01fbc51fd1d10e3e1 | |
parent | 905a3313b5dfc491756b5295bcabe9fab92fbda9 (diff) | |
download | bun-ced6201cb0433c11d8b7ca9e60de61b133cc8fab.tar.gz bun-ced6201cb0433c11d8b7ca9e60de61b133cc8fab.tar.zst bun-ced6201cb0433c11d8b7ca9e60de61b133cc8fab.zip |
Cleanup error handling in Bun.listen
Diffstat (limited to '')
-rw-r--r-- | src/bun.js/api/bun/socket.zig | 211 | ||||
-rw-r--r-- | src/darwin_c.zig | 14 | ||||
-rw-r--r-- | src/linux_c.zig | 14 |
3 files changed, 149 insertions, 90 deletions
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index 4073decde..ec8426eff 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -55,6 +55,16 @@ const ZigString = JSC.ZigString; // } // }; +fn normalizeHost(input: anytype) @TypeOf(input) { + if (input.len == 0) { + return "localhost"; + } + + if (strings.eqlComptime(input, "localhost")) + return "127.0.0.1"; + + return input; +} const Handlers = struct { onOpen: JSC.JSValue = .zero, onClose: JSC.JSValue = .zero, @@ -131,7 +141,7 @@ const Handlers = struct { }; if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) { - exception.* = JSC.toInvalidArguments("Expected socket object", .{}, globalObject).asObjectRef(); + exception.* = JSC.toInvalidArguments("Expected \"socket\" to be an object", .{}, globalObject).asObjectRef(); return null; } @@ -366,7 +376,7 @@ pub const Listener = struct { return .zero; } - const socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse { + var socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse { return .zero; }; var hostname_or_unix = socket_config.hostname_or_unix; @@ -377,54 +387,52 @@ pub const Listener = struct { const ssl_enabled = ssl != null; - var socket = Listener{ - .handlers = handlers, - .connection = if (port) |port_| .{ - .host = .{ .host = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), .port = port_ }, - } else .{ - .unix = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), - }, - .ssl = ssl_enabled, - }; - - socket.handlers.protect(); - - if (socket_config.default_data != .zero) { - socket.strong_data = JSC.Strong.create(socket_config.default_data, globalObject); - } - const socket_flags: i32 = 0; - var ctx_opts: uws.us_socket_context_options_t = undefined; - @memset(@ptrCast([*]u8, &ctx_opts), 0, @sizeOf(uws.us_socket_context_options_t)); - - if (ssl) |ssl_config| { - ctx_opts.key_file_name = ssl_config.key_file_name; - ctx_opts.cert_file_name = ssl_config.cert_file_name; - ctx_opts.ca_file_name = ssl_config.ca_file_name; - ctx_opts.dh_params_file_name = ssl_config.dh_params_file_name; - ctx_opts.passphrase = ssl_config.passphrase; - ctx_opts.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode); - } - + const ctx_opts: uws.us_socket_context_options_t = brk: { + var sock_ctx: uws.us_socket_context_options_t = undefined; + @memset(@ptrCast([*]u8, &sock_ctx), 0, @sizeOf(uws.us_socket_context_options_t)); + + if (ssl) |ssl_config| { + sock_ctx.key_file_name = ssl_config.key_file_name; + sock_ctx.cert_file_name = ssl_config.cert_file_name; + sock_ctx.ca_file_name = ssl_config.ca_file_name; + sock_ctx.dh_params_file_name = ssl_config.dh_params_file_name; + sock_ctx.passphrase = ssl_config.passphrase; + sock_ctx.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode); + } + break :brk sock_ctx; + }; + defer if (ssl != null) ssl.?.deinit(); globalObject.bunVM().eventLoop().ensureWaker(); - socket.socket_context = uws.us_create_socket_context(@boolToInt(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts); - if (ssl) |ssl_config| { - uws.us_socket_context_add_server_name(1, socket.socket_context, ssl_config.server_name, ctx_opts, null); - } + var socket_context = uws.us_create_socket_context( + @boolToInt(ssl_enabled), + uws.Loop.get().?, + @sizeOf(usize), + ctx_opts, + ) orelse { + var err = globalObject.createErrorInstance("Failed to listen on {s}:{d}", .{ hostname_or_unix.slice(), port orelse 0 }); + defer { + socket_config.handlers.unprotect(); + hostname_or_unix.deinit(); + } - var this: *Listener = handlers.vm.allocator.create(Listener) catch @panic("OOM"); - this.* = socket; - this.socket_context.?.ext(ssl_enabled, *Listener).?.* = this; + const errno = @enumToInt(std.c.getErrno(-1)); + if (errno != 0) { + err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno)); + if (bun.C.SystemErrno.init(errno)) |str| { + err.put(globalObject, ZigString.static("code"), ZigString.init(@tagName(str)).toValueGC(globalObject)); + } + } - var this_value = this.toJS(globalObject); - this.strong_self.set(globalObject, this_value); - this.poll_ref.ref(handlers.vm); + exception.* = err.asObjectRef(); + return .zero; + }; if (ssl_enabled) { uws.NewSocketHandler(true).configure( - this.socket_context.?, + socket_context, true, *TLSSocket, struct { @@ -440,7 +448,7 @@ pub const Listener = struct { ); } else { uws.NewSocketHandler(false).configure( - this.socket_context.?, + socket_context, true, *TCPSocket, struct { @@ -456,59 +464,82 @@ pub const Listener = struct { ); } - switch (this.connection) { - .host => |c| { - var host = bun.default_allocator.dupeZ(u8, c.host) catch unreachable; - defer bun.default_allocator.destroy(host.ptr); - this.listener = uws.us_socket_context_listen( - @boolToInt(ssl_enabled), - this.socket_context, - // workaround issue with IPv6 localhost with getaddrinfo() - if (strings.eqlComptime(c.host, "localhost")) - "127.0.0.1" - else - host, - c.port, - socket_flags, - 8, - ) orelse { - exception.* = JSC.toInvalidArguments( - "Failed to listen at {s}:{d}", - .{ - bun.span(host), - c.port, - }, - globalObject, - ).asObjectRef(); - this.poll_ref.unref(handlers.vm); + const connection: Listener.UnixOrHost = if (port) |port_| .{ + .host = .{ .host = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), .port = port_ }, + } else .{ + .unix = (hostname_or_unix.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(), + }; - this.strong_self.clear(); - this.strong_data.clear(); + var listen_socket: *uws.ListenSocket = brk: { + switch (connection) { + .host => |c| { + var host = bun.default_allocator.dupeZ(u8, c.host) catch unreachable; + defer bun.default_allocator.free(host); + break :brk uws.us_socket_context_listen( + @boolToInt(ssl_enabled), + socket_context, + normalizeHost(@as([:0]const u8, host)), + c.port, + socket_flags, + 8, + ); + }, + .unix => |u| { + var host = bun.default_allocator.dupeZ(u8, u) catch unreachable; + defer bun.default_allocator.free(host); + break :brk uws.us_socket_context_listen_unix(@boolToInt(ssl_enabled), socket_context, host, socket_flags, 8); + }, + } + } orelse { + defer { + hostname_or_unix.deinit(); + uws.us_socket_context_free(@boolToInt(ssl_enabled), socket_context); + } - return .zero; - }; - }, - .unix => |u| { - var host = bun.default_allocator.dupeZ(u8, u) catch unreachable; - defer bun.default_allocator.destroy(host.ptr); - this.listener = uws.us_socket_context_listen_unix(@boolToInt(ssl_enabled), this.socket_context, host, socket_flags, 8) orelse { - exception.* = JSC.toInvalidArguments( - "Failed to listen on socket {s}", - .{ - bun.span(host), - }, - globalObject, - ).asObjectRef(); - this.poll_ref.unref(handlers.vm); + const err = globalObject.createErrorInstance( + "Failed to listen at {s}", + .{ + bun.span(hostname_or_unix.slice()), + }, + ); + const errno = @enumToInt(std.c.getErrno(-1)); + if (errno != 0) { + err.put(globalObject, ZigString.static("errno"), JSValue.jsNumber(errno)); + if (bun.C.SystemErrno.init(errno)) |str| { + err.put(globalObject, ZigString.static("code"), ZigString.init(@tagName(str)).toValueGC(globalObject)); + } + } + exception.* = err.asObjectRef(); - this.strong_self.clear(); - this.strong_data.clear(); + return .zero; + }; - return .zero; - }; - }, + var socket = Listener{ + .handlers = handlers, + .connection = connection, + .ssl = ssl_enabled, + .socket_context = socket_context, + .listener = listen_socket, + }; + + socket.handlers.protect(); + + if (socket_config.default_data != .zero) { + socket.strong_data = JSC.Strong.create(socket_config.default_data, globalObject); } + if (ssl) |ssl_config| { + uws.us_socket_context_add_server_name(1, socket.socket_context, ssl_config.server_name, ctx_opts, null); + } + + var this: *Listener = handlers.vm.allocator.create(Listener) catch @panic("OOM"); + this.* = socket; + this.socket_context.?.ext(ssl_enabled, *Listener).?.* = this; + + var this_value = this.toJS(globalObject); + this.strong_self.set(globalObject, this_value); + this.poll_ref.ref(handlers.vm); + return this_value; } @@ -819,7 +850,7 @@ fn NewSocket(comptime ssl: bool) type { switch (connection) { .host => |c| { _ = @This().Socket.connectPtr( - c.host, + normalizeHost(c.host), c.port, socket_ctx, @This(), diff --git a/src/darwin_c.zig b/src/darwin_c.zig index 37fefb2bd..5fe343bc0 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -285,6 +285,20 @@ pub const SystemErrno = enum(u8) { pub const max = 107; + pub fn init(code: anytype) ?SystemErrno { + if (comptime std.meta.trait.isSignedInt(@TypeOf(code))) { + if (code < 0) + return init(-code); + } + + if (code >= max) return null; + return @intToEnum(SystemErrno, code); + } + + pub fn label(this: SystemErrno) ?[]const u8 { + return labels.get(this) orelse null; + } + const LabelMap = std.EnumMap(SystemErrno, []const u8); pub const labels: LabelMap = brk: { var map: LabelMap = LabelMap.initFull(""); diff --git a/src/linux_c.zig b/src/linux_c.zig index 2ff96c966..b652a6490 100644 --- a/src/linux_c.zig +++ b/src/linux_c.zig @@ -141,6 +141,20 @@ pub const SystemErrno = enum(u8) { pub const max = 134; + pub fn init(code: anytype) ?SystemErrno { + if (comptime std.meta.trait.isSignedInt(@TypeOf(code))) { + if (code < 0) + return init(-code); + } + + if (code >= max) return null; + return @intToEnum(SystemErrno, code); + } + + pub fn label(this: SystemErrno) ?[]const u8 { + return labels.get(this) orelse null; + } + const LabelMap = std.EnumMap(SystemErrno, []const u8); pub const labels: LabelMap = brk: { var map: LabelMap = LabelMap.initFull(""); |