UNPKG

undici

Version:

An HTTP/1.1 client, written from scratch for Node.js

84 lines (66 loc) 2.55 kB
'use strict' const net = require('net') const tls = require('tls') const assert = require('assert') const util = require('./util') const { InvalidArgumentError } = require('./errors') // TODO: session re-use does not wait for the first // connection to resolve the session and might therefore // resolve the same servername multiple times even when // re-use is enabled. class Connector { constructor ({ tls, socketPath, maxCachedSessions }) { this.tls = tls || {} // TODO: Make shallow copy to protect against mutations. if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) { throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero') } this.socketPath = socketPath this.sessionCache = new Map() this.maxCachedSessions = maxCachedSessions == null ? 100 : maxCachedSessions } connect ({ hostname, host, protocol, port, servername }, callback) { let socket if (protocol === 'https:') { servername = servername || this.tls.servername || util.getServerName(host) const session = this.sessionCache.get(servername) || null const opts = { ...this.tls, servername, session } socket = this.socketPath ? tls.connect(this.socketPath, opts) : tls.connect(port || /* istanbul ignore next */ 443, hostname, opts) const cache = this.sessionCache const maxCachedSessions = this.maxCachedSessions socket .on('session', function (session) { assert(this.servername) // cache is disabled if (maxCachedSessions === 0) { return } if (cache.size >= maxCachedSessions) { // remove the oldest session const { value: oldestKey } = cache.keys().next() cache.delete(oldestKey) } cache.set(this.servername, session) }) .on('error', function (err) { assert(this.servername) if (err.code !== 'UND_ERR_INFO') { // TODO (fix): Only delete for session related errors. cache.delete(this.servername) } }) } else { socket = this.socketPath ? net.connect(this.socketPath) : net.connect(port || /* istanbul ignore next */ 80, hostname) } socket .setNoDelay(true) .once(protocol === 'https:' ? 'secureConnect' : 'connect', callback) return socket } } module.exports = (opts) => { return Connector.prototype.connect.bind(new Connector(opts)) }