trouble-in-terror-town/node_modules/tunnel-agent/index.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

244 lines
6.7 KiB
JavaScript

'use strict'
var net = require('net')
, tls = require('tls')
, http = require('http')
, https = require('https')
, events = require('events')
, assert = require('assert')
, util = require('util')
, Buffer = require('safe-buffer').Buffer
;
exports.httpOverHttp = httpOverHttp
exports.httpsOverHttp = httpsOverHttp
exports.httpOverHttps = httpOverHttps
exports.httpsOverHttps = httpsOverHttps
function httpOverHttp(options) {
var agent = new TunnelingAgent(options)
agent.request = http.request
return agent
}
function httpsOverHttp(options) {
var agent = new TunnelingAgent(options)
agent.request = http.request
agent.createSocket = createSecureSocket
agent.defaultPort = 443
return agent
}
function httpOverHttps(options) {
var agent = new TunnelingAgent(options)
agent.request = https.request
return agent
}
function httpsOverHttps(options) {
var agent = new TunnelingAgent(options)
agent.request = https.request
agent.createSocket = createSecureSocket
agent.defaultPort = 443
return agent
}
function TunnelingAgent(options) {
var self = this
self.options = options || {}
self.proxyOptions = self.options.proxy || {}
self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets
self.requests = []
self.sockets = []
self.on('free', function onFree(socket, host, port) {
for (var i = 0, len = self.requests.length; i < len; ++i) {
var pending = self.requests[i]
if (pending.host === host && pending.port === port) {
// Detect the request to connect same origin server,
// reuse the connection.
self.requests.splice(i, 1)
pending.request.onSocket(socket)
return
}
}
socket.destroy()
self.removeSocket(socket)
})
}
util.inherits(TunnelingAgent, events.EventEmitter)
TunnelingAgent.prototype.addRequest = function addRequest(req, options) {
var self = this
// Legacy API: addRequest(req, host, port, path)
if (typeof options === 'string') {
options = {
host: options,
port: arguments[2],
path: arguments[3]
};
}
if (self.sockets.length >= this.maxSockets) {
// We are over limit so we'll add it to the queue.
self.requests.push({host: options.host, port: options.port, request: req})
return
}
// If we are under maxSockets create a new one.
self.createConnection({host: options.host, port: options.port, request: req})
}
TunnelingAgent.prototype.createConnection = function createConnection(pending) {
var self = this
self.createSocket(pending, function(socket) {
socket.on('free', onFree)
socket.on('close', onCloseOrRemove)
socket.on('agentRemove', onCloseOrRemove)
pending.request.onSocket(socket)
function onFree() {
self.emit('free', socket, pending.host, pending.port)
}
function onCloseOrRemove(err) {
self.removeSocket(socket)
socket.removeListener('free', onFree)
socket.removeListener('close', onCloseOrRemove)
socket.removeListener('agentRemove', onCloseOrRemove)
}
})
}
TunnelingAgent.prototype.createSocket = function createSocket(options, cb) {
var self = this
var placeholder = {}
self.sockets.push(placeholder)
var connectOptions = mergeOptions({}, self.proxyOptions,
{ method: 'CONNECT'
, path: options.host + ':' + options.port
, agent: false
}
)
if (connectOptions.proxyAuth) {
connectOptions.headers = connectOptions.headers || {}
connectOptions.headers['Proxy-Authorization'] = 'Basic ' +
Buffer.from(connectOptions.proxyAuth).toString('base64')
}
debug('making CONNECT request')
var connectReq = self.request(connectOptions)
connectReq.useChunkedEncodingByDefault = false // for v0.6
connectReq.once('response', onResponse) // for v0.6
connectReq.once('upgrade', onUpgrade) // for v0.6
connectReq.once('connect', onConnect) // for v0.7 or later
connectReq.once('error', onError)
connectReq.end()
function onResponse(res) {
// Very hacky. This is necessary to avoid http-parser leaks.
res.upgrade = true
}
function onUpgrade(res, socket, head) {
// Hacky.
process.nextTick(function() {
onConnect(res, socket, head)
})
}
function onConnect(res, socket, head) {
connectReq.removeAllListeners()
socket.removeAllListeners()
if (res.statusCode === 200) {
assert.equal(head.length, 0)
debug('tunneling connection has established')
self.sockets[self.sockets.indexOf(placeholder)] = socket
cb(socket)
} else {
debug('tunneling socket could not be established, statusCode=%d', res.statusCode)
var error = new Error('tunneling socket could not be established, ' + 'statusCode=' + res.statusCode)
error.code = 'ECONNRESET'
options.request.emit('error', error)
self.removeSocket(placeholder)
}
}
function onError(cause) {
connectReq.removeAllListeners()
debug('tunneling socket could not be established, cause=%s\n', cause.message, cause.stack)
var error = new Error('tunneling socket could not be established, ' + 'cause=' + cause.message)
error.code = 'ECONNRESET'
options.request.emit('error', error)
self.removeSocket(placeholder)
}
}
TunnelingAgent.prototype.removeSocket = function removeSocket(socket) {
var pos = this.sockets.indexOf(socket)
if (pos === -1) return
this.sockets.splice(pos, 1)
var pending = this.requests.shift()
if (pending) {
// If we have pending requests and a socket gets closed a new one
// needs to be created to take over in the pool for the one that closed.
this.createConnection(pending)
}
}
function createSecureSocket(options, cb) {
var self = this
TunnelingAgent.prototype.createSocket.call(self, options, function(socket) {
// 0 is dummy port for v0.6
var secureSocket = tls.connect(0, mergeOptions({}, self.options,
{ servername: options.host
, socket: socket
}
))
self.sockets[self.sockets.indexOf(socket)] = secureSocket
cb(secureSocket)
})
}
function mergeOptions(target) {
for (var i = 1, len = arguments.length; i < len; ++i) {
var overrides = arguments[i]
if (typeof overrides === 'object') {
var keys = Object.keys(overrides)
for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
var k = keys[j]
if (overrides[k] !== undefined) {
target[k] = overrides[k]
}
}
}
}
return target
}
var debug
if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
debug = function() {
var args = Array.prototype.slice.call(arguments)
if (typeof args[0] === 'string') {
args[0] = 'TUNNEL: ' + args[0]
} else {
args.unshift('TUNNEL:')
}
console.error.apply(console, args)
}
} else {
debug = function() {}
}
exports.debug = debug // for test