trouble-in-terror-town/node_modules/got/source/utils/timed-out.js
Mikolaj 2bbacbea09 did some more work on networking and removed EOS in favor of LRM
did some more work on networking and removed EOS in favor of Light Reflective Mirror
2022-05-31 15:04:31 +02:00

160 lines
4.3 KiB
JavaScript

'use strict';
const net = require('net');
class TimeoutError extends Error {
constructor(threshold, event) {
super(`Timeout awaiting '${event}' for ${threshold}ms`);
this.name = 'TimeoutError';
this.code = 'ETIMEDOUT';
this.event = event;
}
}
const reentry = Symbol('reentry');
const noop = () => {};
module.exports = (request, delays, options) => {
/* istanbul ignore next: this makes sure timed-out isn't called twice */
if (request[reentry]) {
return;
}
request[reentry] = true;
let stopNewTimeouts = false;
const addTimeout = (delay, callback, ...args) => {
// An error had been thrown before. Going further would result in uncaught errors.
// See https://github.com/sindresorhus/got/issues/631#issuecomment-435675051
if (stopNewTimeouts) {
return noop;
}
// Event loop order is timers, poll, immediates.
// The timed event may emit during the current tick poll phase, so
// defer calling the handler until the poll phase completes.
let immediate;
const timeout = setTimeout(() => {
immediate = setImmediate(callback, delay, ...args);
/* istanbul ignore next: added in node v9.7.0 */
if (immediate.unref) {
immediate.unref();
}
}, delay);
/* istanbul ignore next: in order to support electron renderer */
if (timeout.unref) {
timeout.unref();
}
const cancel = () => {
clearTimeout(timeout);
clearImmediate(immediate);
};
cancelers.push(cancel);
return cancel;
};
const {host, hostname} = options;
const timeoutHandler = (delay, event) => {
request.emit('error', new TimeoutError(delay, event));
request.once('error', () => {}); // Ignore the `socket hung up` error made by request.abort()
request.abort();
};
const cancelers = [];
const cancelTimeouts = () => {
stopNewTimeouts = true;
cancelers.forEach(cancelTimeout => cancelTimeout());
};
request.once('error', cancelTimeouts);
request.once('response', response => {
response.once('end', cancelTimeouts);
});
if (delays.request !== undefined) {
addTimeout(delays.request, timeoutHandler, 'request');
}
if (delays.socket !== undefined) {
const socketTimeoutHandler = () => {
timeoutHandler(delays.socket, 'socket');
};
request.setTimeout(delays.socket, socketTimeoutHandler);
// `request.setTimeout(0)` causes a memory leak.
// We can just remove the listener and forget about the timer - it's unreffed.
// See https://github.com/sindresorhus/got/issues/690
cancelers.push(() => request.removeListener('timeout', socketTimeoutHandler));
}
if (delays.lookup !== undefined && !request.socketPath && !net.isIP(hostname || host)) {
request.once('socket', socket => {
/* istanbul ignore next: hard to test */
if (socket.connecting) {
const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup');
socket.once('lookup', cancelTimeout);
}
});
}
if (delays.connect !== undefined) {
request.once('socket', socket => {
/* istanbul ignore next: hard to test */
if (socket.connecting) {
const timeConnect = () => addTimeout(delays.connect, timeoutHandler, 'connect');
if (request.socketPath || net.isIP(hostname || host)) {
socket.once('connect', timeConnect());
} else {
socket.once('lookup', error => {
if (error === null) {
socket.once('connect', timeConnect());
}
});
}
}
});
}
if (delays.secureConnect !== undefined && options.protocol === 'https:') {
request.once('socket', socket => {
/* istanbul ignore next: hard to test */
if (socket.connecting) {
socket.once('connect', () => {
const cancelTimeout = addTimeout(delays.secureConnect, timeoutHandler, 'secureConnect');
socket.once('secureConnect', cancelTimeout);
});
}
});
}
if (delays.send !== undefined) {
request.once('socket', socket => {
const timeRequest = () => addTimeout(delays.send, timeoutHandler, 'send');
/* istanbul ignore next: hard to test */
if (socket.connecting) {
socket.once('connect', () => {
request.once('upload-complete', timeRequest());
});
} else {
request.once('upload-complete', timeRequest());
}
});
}
if (delays.response !== undefined) {
request.once('upload-complete', () => {
const cancelTimeout = addTimeout(delays.response, timeoutHandler, 'response');
request.once('response', cancelTimeout);
});
}
};
module.exports.TimeoutError = TimeoutError;