@@ -32,7 +32,7 @@ class DNSInstance {
32
32
33
33
// If full, we just return the origin
34
34
if ( ips == null && this . full ) {
35
- cb ( null , origin . origin )
35
+ cb ( null , origin )
36
36
return
37
37
}
38
38
@@ -74,9 +74,9 @@ class DNSInstance {
74
74
75
75
cb (
76
76
null ,
77
- `${ origin . protocol } //${
77
+ new URL ( `${ origin . protocol } //${
78
78
ip . family === 6 ? `[${ ip . address } ]` : ip . address
79
- } ${ port } `
79
+ } ${ port } `)
80
80
)
81
81
} )
82
82
} else {
@@ -105,9 +105,9 @@ class DNSInstance {
105
105
106
106
cb (
107
107
null ,
108
- `${ origin . protocol } //${
108
+ new URL ( `${ origin . protocol } //${
109
109
ip . family === 6 ? `[${ ip . address } ]` : ip . address
110
- } ${ port } `
110
+ } ${ port } `)
111
111
)
112
112
}
113
113
}
@@ -192,6 +192,38 @@ class DNSInstance {
192
192
return ip
193
193
}
194
194
195
+ pickFamily ( origin , ipFamily ) {
196
+ const records = this . #records. get ( origin . hostname ) ?. records
197
+ if ( ! records ) {
198
+ return null
199
+ }
200
+
201
+ const family = records [ ipFamily ]
202
+ if ( ! family ) {
203
+ return null
204
+ }
205
+
206
+ if ( family . offset == null || family . offset === maxInt ) {
207
+ family . offset = 0
208
+ } else {
209
+ family . offset ++
210
+ }
211
+
212
+ const position = family . offset % family . ips . length
213
+ const ip = family . ips [ position ] ?? null
214
+ if ( ip == null ) {
215
+ return ip
216
+ }
217
+
218
+ if ( Date . now ( ) - ip . timestamp > ip . ttl ) { // record TTL is already in ms
219
+ // We delete expired records
220
+ // It is possible that they have different TTL, so we manage them individually
221
+ family . ips . splice ( position , 1 )
222
+ }
223
+
224
+ return ip
225
+ }
226
+
195
227
setRecords ( origin , addresses ) {
196
228
const timestamp = Date . now ( )
197
229
const records = { records : { 4 : null , 6 : null } }
@@ -228,10 +260,13 @@ class DNSDispatchHandler extends DecoratorHandler {
228
260
#dispatch = null
229
261
#origin = null
230
262
#controller = null
263
+ #newOrigin = null
264
+ #firstTry = true
231
265
232
- constructor ( state , { origin, handler, dispatch } , opts ) {
266
+ constructor ( state , { origin, handler, dispatch, newOrigin } , opts ) {
233
267
super ( handler )
234
268
this . #origin = origin
269
+ this . #newOrigin = newOrigin
235
270
this . #opts = { ...opts }
236
271
this . #state = state
237
272
this . #dispatch = dispatch
@@ -242,21 +277,36 @@ class DNSDispatchHandler extends DecoratorHandler {
242
277
case 'ETIMEDOUT' :
243
278
case 'ECONNREFUSED' : {
244
279
if ( this . #state. dualStack ) {
245
- // We delete the record and retry
246
- this . #state. runLookup ( this . #origin, this . #opts, ( err , newOrigin ) => {
247
- if ( err ) {
248
- super . onResponseError ( controller , err )
249
- return
250
- }
251
-
252
- const dispatchOpts = {
253
- ...this . #opts,
254
- origin : newOrigin
255
- }
280
+ if ( ! this . #firstTry) {
281
+ super . onResponseError ( controller , err )
282
+ return
283
+ }
284
+ this . #firstTry = false
285
+
286
+ // Pick an ip address from the other family
287
+ const otherFamily = this . #newOrigin. hostname [ 0 ] === '[' ? 4 : 6
288
+ const ip = this . #state. pickFamily ( this . #origin, otherFamily )
289
+ if ( ip == null ) {
290
+ super . onResponseError ( controller , err )
291
+ return
292
+ }
256
293
257
- this . #dispatch( dispatchOpts , this )
258
- } )
294
+ let port
295
+ if ( typeof ip . port === 'number' ) {
296
+ port = `:${ ip . port } `
297
+ } else if ( this . #origin. port !== '' ) {
298
+ port = `:${ this . #origin. port } `
299
+ } else {
300
+ port = ''
301
+ }
259
302
303
+ const dispatchOpts = {
304
+ ...this . #opts,
305
+ origin : `${ this . #origin. protocol } //${
306
+ ip . family === 6 ? `[${ ip . address } ]` : ip . address
307
+ } ${ port } `
308
+ }
309
+ this . #dispatch( dispatchOpts , this )
260
310
return
261
311
}
262
312
@@ -266,7 +316,8 @@ class DNSDispatchHandler extends DecoratorHandler {
266
316
}
267
317
case 'ENOTFOUND' :
268
318
this . #state. deleteRecords ( this . #origin)
269
- // eslint-disable-next-line no-fallthrough
319
+ super . onResponseError ( controller , err )
320
+ break
270
321
default :
271
322
super . onResponseError ( controller , err )
272
323
break
@@ -356,11 +407,10 @@ module.exports = interceptorOpts => {
356
407
return handler . onResponseError ( null , err )
357
408
}
358
409
359
- let dispatchOpts = null
360
- dispatchOpts = {
410
+ const dispatchOpts = {
361
411
...origDispatchOpts ,
362
412
servername : origin . hostname , // For SNI on TLS
363
- origin : newOrigin ,
413
+ origin : newOrigin . origin ,
364
414
headers : {
365
415
host : origin . host ,
366
416
...origDispatchOpts . headers
@@ -369,7 +419,10 @@ module.exports = interceptorOpts => {
369
419
370
420
dispatch (
371
421
dispatchOpts ,
372
- instance . getHandler ( { origin, dispatch, handler } , origDispatchOpts )
422
+ instance . getHandler (
423
+ { origin, dispatch, handler, newOrigin } ,
424
+ origDispatchOpts
425
+ )
373
426
)
374
427
} )
375
428
0 commit comments