First Push
This commit is contained in:
348
node_modules/global-tunnel-ng/index.js
generated
vendored
Normal file
348
node_modules/global-tunnel-ng/index.js
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
/* jshint node:true */
|
||||
'use strict';
|
||||
/**
|
||||
* @fileOverview
|
||||
* Global proxy settings.
|
||||
*/
|
||||
var globalTunnel = exports;
|
||||
exports.constructor = function() {};
|
||||
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
var urlParse = require('url').parse;
|
||||
var urlStringify = require('url').format;
|
||||
|
||||
var pick = require('lodash/pick');
|
||||
var assign = require('lodash/assign');
|
||||
var clone = require('lodash/clone');
|
||||
var tunnel = require('tunnel');
|
||||
var npmConfig = require('npm-conf');
|
||||
var encodeUrl = require('encodeurl');
|
||||
|
||||
var agents = require('./lib/agents');
|
||||
exports.agents = agents;
|
||||
|
||||
var ENV_VAR_PROXY_SEARCH_ORDER = [
|
||||
'https_proxy',
|
||||
'HTTPS_PROXY',
|
||||
'http_proxy',
|
||||
'HTTP_PROXY'
|
||||
];
|
||||
var NPM_CONFIG_PROXY_SEARCH_ORDER = ['https-proxy', 'http-proxy', 'proxy'];
|
||||
|
||||
// Save the original settings for restoration later.
|
||||
var ORIGINALS = {
|
||||
http: pick(http, 'globalAgent', ['request', 'get']),
|
||||
https: pick(https, 'globalAgent', ['request', 'get']),
|
||||
env: pick(process.env, ENV_VAR_PROXY_SEARCH_ORDER)
|
||||
};
|
||||
|
||||
var loggingEnabled =
|
||||
process &&
|
||||
process.env &&
|
||||
process.env.DEBUG &&
|
||||
process.env.DEBUG.toLowerCase().indexOf('global-tunnel') !== -1 &&
|
||||
console &&
|
||||
typeof console.log === 'function';
|
||||
|
||||
function log(message) {
|
||||
if (loggingEnabled) {
|
||||
console.log('DEBUG global-tunnel: ' + message);
|
||||
}
|
||||
}
|
||||
|
||||
function resetGlobals() {
|
||||
assign(http, ORIGINALS.http);
|
||||
assign(https, ORIGINALS.https);
|
||||
var val;
|
||||
for (var key in ORIGINALS.env) {
|
||||
if (Object.prototype.hasOwnProperty.call(ORIGINALS.env, key)) {
|
||||
val = ORIGINALS.env[key];
|
||||
if (val !== null && val !== undefined) {
|
||||
process.env[key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the de facto `http_proxy` environment.
|
||||
*/
|
||||
function tryParse(url) {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var parsed = urlParse(url);
|
||||
|
||||
return {
|
||||
protocol: parsed.protocol,
|
||||
host: parsed.hostname,
|
||||
port: parseInt(parsed.port, 10),
|
||||
proxyAuth: parsed.auth
|
||||
};
|
||||
}
|
||||
|
||||
// Stringifies the normalized parsed config
|
||||
function stringifyProxy(conf) {
|
||||
return encodeUrl(
|
||||
urlStringify({
|
||||
protocol: conf.protocol,
|
||||
hostname: conf.host,
|
||||
port: conf.port,
|
||||
auth: conf.proxyAuth
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
globalTunnel.isProxying = false;
|
||||
globalTunnel.proxyUrl = null;
|
||||
globalTunnel.proxyConfig = null;
|
||||
|
||||
function findEnvVarProxy() {
|
||||
var i;
|
||||
var key;
|
||||
var val;
|
||||
var result;
|
||||
for (i = 0; i < ENV_VAR_PROXY_SEARCH_ORDER.length; i++) {
|
||||
key = ENV_VAR_PROXY_SEARCH_ORDER[i];
|
||||
val = process.env[key];
|
||||
if (val !== null && val !== undefined) {
|
||||
// Get the first non-empty
|
||||
result = result || val;
|
||||
// Delete all
|
||||
// NB: we do it here to prevent double proxy handling (and for example path change)
|
||||
// by us and the `request` module or other sub-dependencies
|
||||
delete process.env[key];
|
||||
log('Found proxy in environment variable ' + ENV_VAR_PROXY_SEARCH_ORDER[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
// __GLOBAL_TUNNEL_DEPENDENCY_NPMCONF__ is a hook to override the npm-conf module
|
||||
var config =
|
||||
(global.__GLOBAL_TUNNEL_DEPENDENCY_NPMCONF__ &&
|
||||
global.__GLOBAL_TUNNEL_DEPENDENCY_NPMCONF__()) ||
|
||||
npmConfig();
|
||||
|
||||
for (i = 0; i < NPM_CONFIG_PROXY_SEARCH_ORDER.length && !val; i++) {
|
||||
val = config.get(NPM_CONFIG_PROXY_SEARCH_ORDER[i]);
|
||||
}
|
||||
|
||||
if (val) {
|
||||
log('Found proxy in npm config ' + NPM_CONFIG_PROXY_SEARCH_ORDER[i]);
|
||||
result = val;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the node http/https `globalAgent`s to use the configured proxy.
|
||||
*
|
||||
* If the config is empty, the `http_proxy` environment variable is checked.
|
||||
* If that's not present, the NPM `http-proxy` configuration is checked.
|
||||
* If neither are present no proxying will be enabled.
|
||||
*
|
||||
* @param {object} conf - Options
|
||||
* @param {string} conf.host - Hostname or IP of the HTTP proxy to use
|
||||
* @param {int} conf.port - TCP port of the proxy
|
||||
* @param {string} [conf.protocol='http'] - The protocol of the proxy, 'http' or 'https'
|
||||
* @param {string} [conf.proxyAuth] - Credentials for the proxy in the form userId:password
|
||||
* @param {string} [conf.connect='https'] - Which protocols will use the CONNECT method 'neither', 'https' or 'both'
|
||||
* @param {int} [conf.sockets=5] Maximum number of TCP sockets to use in each pool. There are two different pools for HTTP and HTTPS
|
||||
* @param {object} [conf.httpsOptions] - HTTPS options
|
||||
*/
|
||||
globalTunnel.initialize = function(conf) {
|
||||
// Don't do anything if already proxying.
|
||||
// To change the settings `.end()` should be called first.
|
||||
if (globalTunnel.isProxying) {
|
||||
log('Already proxying');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// This has an effect of also removing the proxy config
|
||||
// from the global env to prevent other modules (like request) doing
|
||||
// double handling
|
||||
var envVarProxy = findEnvVarProxy();
|
||||
|
||||
if (conf && typeof conf === 'string') {
|
||||
// Passed string - parse it as a URL
|
||||
conf = tryParse(conf);
|
||||
} else if (conf) {
|
||||
// Passed object - take it but clone for future mutations
|
||||
conf = clone(conf);
|
||||
} else if (envVarProxy) {
|
||||
// Nothing passed - parse from the env
|
||||
conf = tryParse(envVarProxy);
|
||||
} else {
|
||||
log('No configuration found, not proxying');
|
||||
// No config - do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
log('Proxy configuration to be used is ' + JSON.stringify(conf, null, 2));
|
||||
|
||||
if (!conf.host) {
|
||||
throw new Error('upstream proxy host is required');
|
||||
}
|
||||
if (!conf.port) {
|
||||
throw new Error('upstream proxy port is required');
|
||||
}
|
||||
|
||||
if (conf.protocol === undefined) {
|
||||
conf.protocol = 'http:'; // Default to proxy speaking http
|
||||
}
|
||||
if (!/:$/.test(conf.protocol)) {
|
||||
conf.protocol += ':';
|
||||
}
|
||||
|
||||
if (!conf.connect) {
|
||||
conf.connect = 'https'; // Just HTTPS by default
|
||||
}
|
||||
|
||||
if (['both', 'neither', 'https'].indexOf(conf.connect) < 0) {
|
||||
throw new Error('valid connect options are "neither", "https", or "both"');
|
||||
}
|
||||
|
||||
var connectHttp = conf.connect === 'both';
|
||||
var connectHttps = conf.connect !== 'neither';
|
||||
|
||||
if (conf.httpsOptions) {
|
||||
conf.innerHttpsOpts = conf.httpsOptions;
|
||||
conf.outerHttpsOpts = conf.innerHttpsOpts;
|
||||
}
|
||||
|
||||
http.globalAgent = globalTunnel._makeAgent(conf, 'http', connectHttp);
|
||||
https.globalAgent = globalTunnel._makeAgent(conf, 'https', connectHttps);
|
||||
|
||||
http.request = globalTunnel._makeHttp('request', http, 'http');
|
||||
https.request = globalTunnel._makeHttp('request', https, 'https');
|
||||
http.get = globalTunnel._makeHttp('get', http, 'http');
|
||||
https.get = globalTunnel._makeHttp('get', https, 'https');
|
||||
|
||||
globalTunnel.isProxying = true;
|
||||
globalTunnel.proxyUrl = stringifyProxy(conf);
|
||||
globalTunnel.proxyConfig = clone(conf);
|
||||
} catch (e) {
|
||||
resetGlobals();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
var _makeAgent = function(conf, innerProtocol, useCONNECT) {
|
||||
log('Creating proxying agent');
|
||||
var outerProtocol = conf.protocol;
|
||||
innerProtocol += ':';
|
||||
|
||||
var opts = {
|
||||
proxy: pick(conf, 'host', 'port', 'protocol', 'localAddress', 'proxyAuth'),
|
||||
maxSockets: conf.sockets
|
||||
};
|
||||
opts.proxy.innerProtocol = innerProtocol;
|
||||
|
||||
if (useCONNECT) {
|
||||
if (conf.proxyHttpsOptions) {
|
||||
assign(opts.proxy, conf.proxyHttpsOptions);
|
||||
}
|
||||
if (conf.originHttpsOptions) {
|
||||
assign(opts, conf.originHttpsOptions);
|
||||
}
|
||||
|
||||
if (outerProtocol === 'https:') {
|
||||
if (innerProtocol === 'https:') {
|
||||
return tunnel.httpsOverHttps(opts);
|
||||
}
|
||||
return tunnel.httpOverHttps(opts);
|
||||
}
|
||||
if (innerProtocol === 'https:') {
|
||||
return tunnel.httpsOverHttp(opts);
|
||||
}
|
||||
return tunnel.httpOverHttp(opts);
|
||||
}
|
||||
if (conf.originHttpsOptions) {
|
||||
throw new Error('originHttpsOptions must be combined with a tunnel:true option');
|
||||
}
|
||||
if (conf.proxyHttpsOptions) {
|
||||
// NB: not opts.
|
||||
assign(opts, conf.proxyHttpsOptions);
|
||||
}
|
||||
|
||||
if (outerProtocol === 'https:') {
|
||||
return new agents.OuterHttpsAgent(opts);
|
||||
}
|
||||
return new agents.OuterHttpAgent(opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct an agent based on:
|
||||
* - is the connection to the proxy secure?
|
||||
* - is the connection to the origin secure?
|
||||
* - the address of the proxy
|
||||
*/
|
||||
globalTunnel._makeAgent = function(conf, innerProtocol, useCONNECT) {
|
||||
var agent = _makeAgent(conf, innerProtocol, useCONNECT);
|
||||
// Set the protocol to match that of the target request type
|
||||
agent.protocol = innerProtocol + ':';
|
||||
return agent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for http/https, makes sure to default the agent
|
||||
* to the global agent. Due to how node implements it in lib/http.js, the
|
||||
* globalAgent we define won't get used (node uses a module-scoped variable,
|
||||
* not the exports field).
|
||||
* @param {string} method 'request' or 'get', http/https methods
|
||||
* @param {string|object} options http/https request url or options
|
||||
* @param {function} [cb]
|
||||
* @private
|
||||
*/
|
||||
globalTunnel._makeHttp = function(method, httpOrHttps, protocol) {
|
||||
return function(options, callback) {
|
||||
if (typeof options === 'string') {
|
||||
options = urlParse(options);
|
||||
} else {
|
||||
options = clone(options);
|
||||
}
|
||||
|
||||
// Respect the default agent provided by node's lib/https.js
|
||||
if (
|
||||
(options.agent === null || options.agent === undefined) &&
|
||||
typeof options.createConnection !== 'function' &&
|
||||
(options.host || options.hostname)
|
||||
) {
|
||||
options.agent = options._defaultAgent || httpOrHttps.globalAgent;
|
||||
}
|
||||
|
||||
// Set the default port ourselves to prevent Node doing it based on the proxy agent protocol
|
||||
if (options.protocol === 'https:' || (!options.protocol && protocol === 'https')) {
|
||||
options.port = options.port || 443;
|
||||
}
|
||||
if (options.protocol === 'http:' || (!options.protocol && protocol === 'http')) {
|
||||
options.port = options.port || 80;
|
||||
}
|
||||
|
||||
log(
|
||||
'Requesting to ' +
|
||||
(options.protocol || protocol) +
|
||||
'//' +
|
||||
(options.host || options.hostname) +
|
||||
':' +
|
||||
options.port
|
||||
);
|
||||
|
||||
return ORIGINALS[protocol][method].call(httpOrHttps, options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Restores global http/https agents.
|
||||
*/
|
||||
globalTunnel.end = function() {
|
||||
resetGlobals();
|
||||
globalTunnel.isProxying = false;
|
||||
globalTunnel.proxyUrl = null;
|
||||
globalTunnel.proxyConfig = null;
|
||||
};
|
||||
Reference in New Issue
Block a user