Skip to content

Commit ad09826

Browse files
authored
Merge branch 'main' into feat/open-item-purchase-from-scenes
2 parents 2ede70c + 07a0182 commit ad09826

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

packages/@dcl/sdk-commands/src/logic/get-free-port.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ function tryListen(port: number): Promise<number> {
99
const server = net.createServer()
1010
server.unref()
1111
server.once('error', reject)
12-
server.listen(port, () => {
12+
// probe the same address the servers bind (HTTP_SERVER_HOST=0.0.0.0): a hostless
13+
// listen binds the IPv6 wildcard, which on macOS coexists with an IPv4 listener
14+
// and reports ports as free that the real server then fails to bind (EADDRINUSE)
15+
server.listen(port, '0.0.0.0', () => {
1316
const address = server.address()
1417
server.close(() => resolve(typeof address === 'object' && address ? address.port : port))
1518
})

test/sdk-commands/utils/get-free-port.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@ describe('utils/get-free-port', () => {
2020
expect(result).toBeLessThan(65536)
2121
})
2222

23+
it('never returns a port that is taken on 0.0.0.0, the address the preview server binds', async () => {
24+
// occupy the base port (8000) with an IPv4-only listener, like a leftover preview server;
25+
// a hostless probe binds the IPv6 wildcard and, on macOS, misses this listener entirely
26+
const blocker = net.createServer()
27+
blocker.unref()
28+
const blocked = await new Promise<boolean>((resolve) => {
29+
blocker.once('error', () => resolve(false))
30+
blocker.listen(8000, '0.0.0.0', () => resolve(true))
31+
})
32+
try {
33+
const result = await getPort(NaN, 123)
34+
if (blocked) expect(result).not.toBe(8000)
35+
// the returned port must be bindable on 0.0.0.0, exactly like the real server binds it
36+
const server = net.createServer()
37+
server.unref()
38+
await new Promise<void>((resolve, reject) => {
39+
server.once('error', reject)
40+
server.listen(result, '0.0.0.0', () => resolve())
41+
})
42+
await new Promise((resolve) => server.close(resolve))
43+
} finally {
44+
if (blocked) await new Promise((resolve) => blocker.close(resolve))
45+
}
46+
})
47+
2348
it('should return the fail-over port when probing fails', async () => {
2449
jest.spyOn(net, 'createServer').mockImplementation(() => {
2550
throw new Error('probe failed')

0 commit comments

Comments
 (0)