@nxtedition/nxt-undici 6.0.17 → 6.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/interceptor/dns.js +27 -26
- package/lib/interceptor/dns.test.js +73 -0
- package/lib/utils.js +1 -0
- package/package.json +1 -1
package/lib/interceptor/dns.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import net from 'node:net'
|
|
2
|
-
import
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import * as dns from 'node:dns'
|
|
3
4
|
import { DecoratorHandler, getFastNow } from '../utils.js'
|
|
4
5
|
|
|
5
|
-
const MAX_TTL = 10e3
|
|
6
|
-
|
|
7
6
|
class Handler extends DecoratorHandler {
|
|
8
7
|
#callback
|
|
9
8
|
#statusCode
|
|
@@ -37,33 +36,29 @@ export default () => (dispatch) => {
|
|
|
37
36
|
const cache = new Map()
|
|
38
37
|
const promises = new Map()
|
|
39
38
|
|
|
40
|
-
function resolve(hostname) {
|
|
39
|
+
function resolve(resolve4, hostname) {
|
|
41
40
|
let promise = promises.get(hostname)
|
|
42
41
|
if (!promise) {
|
|
43
42
|
promise = new Promise((resolve) =>
|
|
44
43
|
resolve4(hostname, { ttl: true }, (err, records) => {
|
|
45
|
-
let ret
|
|
46
|
-
|
|
47
44
|
if (err) {
|
|
48
|
-
|
|
45
|
+
resolve([err, null])
|
|
49
46
|
} else {
|
|
50
47
|
const now = getFastNow()
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
})),
|
|
59
|
-
}
|
|
60
|
-
}
|
|
48
|
+
const val = records.map(({ address, ttl }) => ({
|
|
49
|
+
address,
|
|
50
|
+
expires: now + 1e3 * ttl,
|
|
51
|
+
pending: 0,
|
|
52
|
+
errored: 0,
|
|
53
|
+
counter: 0,
|
|
54
|
+
}))
|
|
61
55
|
|
|
62
|
-
|
|
56
|
+
cache.set(hostname, val)
|
|
63
57
|
|
|
64
|
-
|
|
58
|
+
resolve([null, val])
|
|
59
|
+
}
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
assert(promises.delete(hostname))
|
|
67
62
|
}),
|
|
68
63
|
)
|
|
69
64
|
promises.set(hostname, promise)
|
|
@@ -87,16 +82,22 @@ export default () => (dispatch) => {
|
|
|
87
82
|
|
|
88
83
|
const now = getFastNow()
|
|
89
84
|
|
|
90
|
-
let records = cache.get(hostname)
|
|
85
|
+
let records = cache.get(hostname)
|
|
86
|
+
|
|
87
|
+
const resolve4 = opts.dns.resolve4 || dns.resolve4
|
|
91
88
|
|
|
92
89
|
if (records == null || records.every((x) => x.expires < now)) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
const [err, val] = await resolve(resolve4, hostname)
|
|
91
|
+
|
|
92
|
+
if (err) {
|
|
93
|
+
throw err
|
|
96
94
|
}
|
|
97
|
-
|
|
95
|
+
|
|
96
|
+
assert(val.every((x) => x.expires > 0))
|
|
97
|
+
|
|
98
|
+
records = val
|
|
98
99
|
} else if (records.some((x) => x.expires < now + 1e3)) {
|
|
99
|
-
resolve(hostname)
|
|
100
|
+
resolve(resolve4, hostname)
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
records.sort(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { once } from 'node:events'
|
|
2
|
+
import http from 'node:http'
|
|
1
3
|
import { test } from 'tap'
|
|
2
4
|
import { request } from '../index.js'
|
|
3
5
|
|
|
@@ -7,3 +9,74 @@ test('retry destroy pre response', async (t) => {
|
|
|
7
9
|
t.equal(statusCode, 200)
|
|
8
10
|
t.end()
|
|
9
11
|
})
|
|
12
|
+
|
|
13
|
+
test('expire & retry on error', async (t) => {
|
|
14
|
+
t.plan(3)
|
|
15
|
+
|
|
16
|
+
const server = http
|
|
17
|
+
.createServer((req, res) => {
|
|
18
|
+
res.end()
|
|
19
|
+
})
|
|
20
|
+
.listen(0)
|
|
21
|
+
t.teardown(server.close.bind(server))
|
|
22
|
+
|
|
23
|
+
await once(server, 'listening')
|
|
24
|
+
|
|
25
|
+
let counter = 0
|
|
26
|
+
const { body } = await request(`http://asd.com:${server.address().port}`, {
|
|
27
|
+
dns: {
|
|
28
|
+
resolve4(hostname, opts, callback) {
|
|
29
|
+
t.pass()
|
|
30
|
+
if (counter++ === 0) {
|
|
31
|
+
process.nextTick(callback, null, [{ address: '11.9.9.9', ttl: 600 }])
|
|
32
|
+
} else {
|
|
33
|
+
process.nextTick(callback, null, [{ address: '127.0.0.1', ttl: 600 }])
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
retry: 2,
|
|
38
|
+
})
|
|
39
|
+
await body.dump()
|
|
40
|
+
|
|
41
|
+
t.pass()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('expire on error', async (t) => {
|
|
45
|
+
t.plan(2)
|
|
46
|
+
|
|
47
|
+
const server = http
|
|
48
|
+
.createServer((req, res) => {
|
|
49
|
+
res.end()
|
|
50
|
+
})
|
|
51
|
+
.listen(0)
|
|
52
|
+
t.teardown(server.close.bind(server))
|
|
53
|
+
|
|
54
|
+
await once(server, 'listening')
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const { body } = await request(`http://123.com:${server.address().port}`, {
|
|
58
|
+
dns: {
|
|
59
|
+
resolve4(hostname, opts, callback) {
|
|
60
|
+
process.nextTick(callback, null, [{ address: '10.9.9.9', ttl: 600 }])
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
retry: false,
|
|
64
|
+
})
|
|
65
|
+
await body.dump()
|
|
66
|
+
} catch (err) {
|
|
67
|
+
t.equal(err.code, 'UND_ERR_CONNECT_TIMEOUT')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const { body } = await request(`http://123.com:${server.address().port}`, {
|
|
71
|
+
dns: {
|
|
72
|
+
resolve4(hostname, opts, callback) {
|
|
73
|
+
process.nextTick(callback, null, [{ address: '127.0.0.1', ttl: 600 }])
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
retry: false,
|
|
77
|
+
})
|
|
78
|
+
await body.dump()
|
|
79
|
+
|
|
80
|
+
console.error('### 4')
|
|
81
|
+
t.pass()
|
|
82
|
+
})
|
package/lib/utils.js
CHANGED
|
@@ -123,6 +123,7 @@ export async function retry(err, retryCount, opts) {
|
|
|
123
123
|
'EHOSTDOWN',
|
|
124
124
|
'EHOSTUNREACH',
|
|
125
125
|
'EPIPE',
|
|
126
|
+
'UND_ERR_CONNECT_TIMEOUT',
|
|
126
127
|
].includes(err.code)
|
|
127
128
|
) {
|
|
128
129
|
return tp.setTimeout(Math.min(10e3, retryCount * 1e3), undefined, { signal: opts.signal })
|