1'use strict'
2
3const dns = require('./dns')
4
5const normalizeOptions = (opts) => {
6  const family = parseInt(opts.family ?? '0', 10)
7  const keepAlive = opts.keepAlive ?? true
8
9  const normalized = {
10    // nodejs http agent options. these are all the defaults
11    // but kept here to increase the likelihood of cache hits
12    // https://nodejs.org/api/http.html#new-agentoptions
13    keepAliveMsecs: keepAlive ? 1000 : undefined,
14    maxSockets: opts.maxSockets ?? 15,
15    maxTotalSockets: Infinity,
16    maxFreeSockets: keepAlive ? 256 : undefined,
17    scheduling: 'fifo',
18    // then spread the rest of the options
19    ...opts,
20    // we already set these to their defaults that we want
21    family,
22    keepAlive,
23    // our custom timeout options
24    timeouts: {
25      // the standard timeout option is mapped to our idle timeout
26      // and then deleted below
27      idle: opts.timeout ?? 0,
28      connection: 0,
29      response: 0,
30      transfer: 0,
31      ...opts.timeouts,
32    },
33    // get the dns options that go at the top level of socket connection
34    ...dns.getOptions({ family, ...opts.dns }),
35  }
36
37  // remove timeout since we already used it to set our own idle timeout
38  delete normalized.timeout
39
40  return normalized
41}
42
43const createKey = (obj) => {
44  let key = ''
45  const sorted = Object.entries(obj).sort((a, b) => a[0] - b[0])
46  for (let [k, v] of sorted) {
47    if (v == null) {
48      v = 'null'
49    } else if (v instanceof URL) {
50      v = v.toString()
51    } else if (typeof v === 'object') {
52      v = createKey(v)
53    }
54    key += `${k}:${v}:`
55  }
56  return key
57}
58
59const cacheOptions = ({ secureEndpoint, ...options }) => createKey({
60  secureEndpoint: !!secureEndpoint,
61  // socket connect options
62  family: options.family,
63  hints: options.hints,
64  localAddress: options.localAddress,
65  // tls specific connect options
66  strictSsl: secureEndpoint ? !!options.rejectUnauthorized : false,
67  ca: secureEndpoint ? options.ca : null,
68  cert: secureEndpoint ? options.cert : null,
69  key: secureEndpoint ? options.key : null,
70  // http agent options
71  keepAlive: options.keepAlive,
72  keepAliveMsecs: options.keepAliveMsecs,
73  maxSockets: options.maxSockets,
74  maxTotalSockets: options.maxTotalSockets,
75  maxFreeSockets: options.maxFreeSockets,
76  scheduling: options.scheduling,
77  // timeout options
78  timeouts: options.timeouts,
79  // proxy
80  proxy: options.proxy,
81})
82
83module.exports = {
84  normalizeOptions,
85  cacheOptions,
86}
87