diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 6320e2bffc..3dda4f1f8a 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -5632,34 +5632,37 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp if (this.listener) |listener| { port = @intCast(listener.getLocalPort()); } + var hostname = this.getCachedHostname().asUTF8(); + if (hostname == null) { + if (tcp.hostname) |name| { + hostname = bun.sliceTo(name, 0); + } else { + hostname = "::"; + } + } break :blk bun.fmt.URLFormatter{ .proto = if (comptime ssl_enabled_) .https else .http, - .hostname = if (tcp.hostname) |hostname| bun.sliceTo(@constCast(hostname), 0) else null, + .hostname = hostname, .port = port, }; }, }; - const buf = std.fmt.allocPrint(default_allocator, "{any}", .{fmt}) catch @panic("Out of memory"); + const buf = std.fmt.allocPrint(default_allocator, "{any}", .{fmt}) catch bun.outOfMemory(); defer default_allocator.free(buf); var value = bun.String.createUTF8(buf); return value.toJSDOMURL(globalThis); } - pub fn getHostname(this: *ThisServer, globalThis: *JSGlobalObject) callconv(.C) JSC.JSValue { - switch (this.config.address) { - .unix => return .undefined, - else => {}, - } - + fn getCachedHostname(this: *ThisServer) bun.String { if (this.cached_hostname.isEmpty()) { if (this.listener) |listener| { - var buf: [1024]u8 = [_]u8{0} ** 1024; - var len: i32 = 1024; - listener.socket().remoteAddress(&buf, &len); - if (len > 0) { - this.cached_hostname = bun.String.createUTF8(buf[0..@as(usize, @intCast(len))]); + const size = 1024; + var buf: [size]u8 = [_]u8{0} ** size; + var is_ipv6: bool = false; + if (listener.socket().localAddressText(&buf, &is_ipv6)) |_addr| { + this.cached_hostname = bun.String.createUTF8(_addr); } } @@ -5676,8 +5679,16 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } } } + return this.cached_hostname; + } - return this.cached_hostname.toJS(globalThis); + pub fn getHostname(this: *ThisServer, globalThis: *JSGlobalObject) callconv(.C) JSC.JSValue { + switch (this.config.address) { + .unix => return .undefined, + else => {}, + } + + return this.getCachedHostname().toJS(globalThis); } pub fn getProtocol(this: *ThisServer, globalThis: *JSGlobalObject) callconv(.C) JSC.JSValue { diff --git a/test/js/bun/http/serve.test.ts b/test/js/bun/http/serve.test.ts index 05caaccf3b..6c7ec024cd 100644 --- a/test/js/bun/http/serve.test.ts +++ b/test/js/bun/http/serve.test.ts @@ -1513,3 +1513,11 @@ it("should resolve pending promise if requested ended with pending read", async }, ); }); + +it("should report :: as hostname when no host is specified", () => { + let server = Bun.serve({ + async fetch(req) {} + }) + expect(server.hostname).toBe("::"); + expect(server.url.href).toMatch("http://[::]:"); +});