@oracle/suitecloud-cli
Version:
SuiteCloud CLI for Node.js
111 lines (96 loc) • 2.86 kB
JavaScript
/*
** Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
*/
;
const http = require('http');
const { URL } = require('url');
const tls = require('tls');
const net = require('net');
const { PROTOCOL, EVENT, METHOD } = require('./HttpConstants');
class ProxyAgent {
constructor(proxyString, agentOptions) {
this.proxyString = proxyString;
this.agentOptions = agentOptions;
this.initProxyURL();
}
initProxyURL() {
try {
const proxy = new URL(this.proxyString);
proxy.host = proxy.hostname || proxy.host;
proxy.port = +proxy.port || (proxy.protocol.toLowerCase() === PROTOCOL.HTTPS ? 443 : 80);
this.proxyURL = proxy;
} catch (err) {
throw new ProxyAgentError(`${err.input} ${ERROR_MESSAGES.BAD_PROXY}`);
}
}
addRequest(req, options) {
req.shouldKeepAlive = false;
this.createConnection(options)
.then((socket) => {
req.onSocket(socket);
})
.catch((err) => {
req.emit(EVENT.ERROR, err);
});
}
createConnection(options) {
return new Promise((resolve, reject) => {
const useSSL = options.protocol ? options.protocol.toLowerCase() === PROTOCOL.HTTPS : false;
if (useSSL && this.agentOptions.tunnel === true) {
if (options.port === 80) options.port = 443;
// CONNECT Method
const req = http.request({
host: this.proxyURL.hostname,
port: this.proxyURL.port,
auth: this.proxyURL.auth,
method: METHOD.CONNECT,
path: (options.hostname || options.host) + ':' + options.port,
headers: {
host: options.host,
},
timeout: this.agentOptions.timeout,
});
req.once(EVENT.CONNECT, (res, socket, head) => {
const tunnel = tls.connect({
socket: socket,
host: options.hostname || options.host,
port: +options.port,
servername: options.servername || options.host,
});
resolve(tunnel);
});
req.once(EVENT.TIMEOUT, () => {
req.destroy();
reject(new ProxyAgentError(ERROR_MESSAGES.CONNECT_TIMEOUT));
});
req.once(EVENT.ERROR, (err) => {
reject(err);
});
req.once(EVENT.CLOSE, () => {
reject(new ProxyAgentError(ERROR_MESSAGES.SERVER_CLOSE_EVENT));
});
req.end();
} else {
const socket = net.connect({
host: this.proxyURL.host,
port: this.proxyURL.port === '' ? 80 : +this.proxyURL.port,
auth: this.proxyURL.auth,
});
resolve(socket);
}
});
}
}
class ProxyAgentError extends Error {
constructor(message) {
super(message);
this.name = 'ProxyAgentError';
}
}
const ERROR_MESSAGES = {
CONNECT_TIMEOUT: 'CONNECT request timeout.',
SERVER_CLOSE_EVENT: 'Tunnel failed. Socket closed prematurely.',
BAD_PROXY: 'is not a valid value for proxy.'
}
module.exports = ProxyAgent;