UNPKG

undici

Version:

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

123 lines (99 loc) 3.07 kB
'use strict' const { connect } = require('node:net') const { kClose, kDestroy } = require('../core/symbols') const { InvalidArgumentError } = require('../core/errors') const util = require('../core/util') const Client = require('./client') const DispatcherBase = require('./dispatcher-base') class H2CClient extends DispatcherBase { #client = null constructor (origin, clientOpts) { super() if (typeof origin === 'string') { origin = new URL(origin) } if (origin.protocol !== 'http:') { throw new InvalidArgumentError( 'h2c-client: Only h2c protocol is supported' ) } const { connect, maxConcurrentStreams, pipelining, ...opts } = clientOpts ?? {} let defaultMaxConcurrentStreams = 100 let defaultPipelining = 100 if ( maxConcurrentStreams != null && Number.isInteger(maxConcurrentStreams) && maxConcurrentStreams > 0 ) { defaultMaxConcurrentStreams = maxConcurrentStreams } if (pipelining != null && Number.isInteger(pipelining) && pipelining > 0) { defaultPipelining = pipelining } if (defaultPipelining > defaultMaxConcurrentStreams) { throw new InvalidArgumentError( 'h2c-client: pipelining cannot be greater than maxConcurrentStreams' ) } this.#client = new Client(origin, { ...opts, connect: this.#buildConnector(connect), maxConcurrentStreams: defaultMaxConcurrentStreams, pipelining: defaultPipelining, allowH2: true }) } #buildConnector (connectOpts) { return (opts, callback) => { const timeout = connectOpts?.connectOpts ?? 10e3 const { hostname, port, pathname } = opts const socket = connect({ ...opts, host: hostname, port, pathname }) // Set TCP keep alive options on the socket here instead of in connect() for the case of assigning the socket if (opts.keepAlive == null || opts.keepAlive) { const keepAliveInitialDelay = opts.keepAliveInitialDelay == null ? 60e3 : opts.keepAliveInitialDelay socket.setKeepAlive(true, keepAliveInitialDelay) } socket.alpnProtocol = 'h2' const clearConnectTimeout = util.setupConnectTimeout( new WeakRef(socket), { timeout, hostname, port } ) socket .setNoDelay(true) .once('connect', function () { queueMicrotask(clearConnectTimeout) if (callback) { const cb = callback callback = null cb(null, this) } }) .on('error', function (err) { queueMicrotask(clearConnectTimeout) if (callback) { const cb = callback callback = null cb(err) } }) return socket } } dispatch (opts, handler) { return this.#client.dispatch(opts, handler) } async [kClose] () { await this.#client.close() } async [kDestroy] () { await this.#client.destroy() } } module.exports = H2CClient