144 lines
3.5 KiB
JavaScript
144 lines
3.5 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
/**
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
var co = require('co');
|
||
|
var vm = require('vm');
|
||
|
var parse = require('url').parse;
|
||
|
var thunkify = require('thunkify');
|
||
|
var degenerator = require('degenerator');
|
||
|
|
||
|
/**
|
||
|
* Built-in PAC functions.
|
||
|
*/
|
||
|
|
||
|
var dateRange = require('./dateRange');
|
||
|
var dnsDomainIs = require('./dnsDomainIs');
|
||
|
var dnsDomainLevels = require('./dnsDomainLevels');
|
||
|
var dnsResolve = require('./dnsResolve');
|
||
|
var isInNet = require('./isInNet');
|
||
|
var isPlainHostName = require('./isPlainHostName');
|
||
|
var isResolvable = require('./isResolvable');
|
||
|
var localHostOrDomainIs = require('./localHostOrDomainIs');
|
||
|
var myIpAddress = require('./myIpAddress');
|
||
|
var shExpMatch = require('./shExpMatch');
|
||
|
var timeRange = require('./timeRange');
|
||
|
var weekdayRange = require('./weekdayRange');
|
||
|
|
||
|
/**
|
||
|
* Module exports.
|
||
|
*/
|
||
|
|
||
|
module.exports = generate;
|
||
|
|
||
|
/**
|
||
|
* Returns an asyncronous `FindProxyForURL` function from the
|
||
|
* given JS string (from a PAC file).
|
||
|
*
|
||
|
* @param {String} str JS string
|
||
|
* @param {Object} opts optional "options" object
|
||
|
* @return {Function} async resolver function
|
||
|
*/
|
||
|
|
||
|
function generate (_str, opts) {
|
||
|
var i;
|
||
|
var str = String(_str)
|
||
|
|
||
|
// the sandbox to use for the vm
|
||
|
var sandbox = {
|
||
|
dateRange: dateRange,
|
||
|
dnsDomainIs: dnsDomainIs,
|
||
|
dnsDomainLevels: dnsDomainLevels,
|
||
|
dnsResolve: dnsResolve,
|
||
|
isInNet: isInNet,
|
||
|
isPlainHostName: isPlainHostName,
|
||
|
isResolvable: isResolvable,
|
||
|
localHostOrDomainIs: localHostOrDomainIs,
|
||
|
myIpAddress: myIpAddress,
|
||
|
shExpMatch: shExpMatch,
|
||
|
timeRange: timeRange,
|
||
|
weekdayRange: weekdayRange
|
||
|
};
|
||
|
|
||
|
// copy the properties from the user-provided `sandbox` onto ours
|
||
|
if (opts && opts.sandbox) {
|
||
|
for (i in opts.sandbox) {
|
||
|
sandbox[i] = opts.sandbox[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// construct the array of async function names to add `yield` calls to.
|
||
|
// user-provided async functions added to the `sandbox` must have an
|
||
|
// `async = true` property set on the function instance
|
||
|
var names = [];
|
||
|
for (i in sandbox) {
|
||
|
if (sandbox[i].async) {
|
||
|
names.push(i);
|
||
|
sandbox[i] = thunkify(sandbox[i]);
|
||
|
}
|
||
|
}
|
||
|
//console.log(names);
|
||
|
|
||
|
// convert the JS FindProxyForURL function into a generator function
|
||
|
var js = degenerator(str, names);
|
||
|
|
||
|
// filename of the pac file for the vm
|
||
|
var filename = (opts && opts.filename) || 'proxy.pac';
|
||
|
|
||
|
// evaluate the JS string and extract the FindProxyForURL generator function
|
||
|
var fn = vm.runInNewContext(js + ';FindProxyForURL', sandbox, filename);
|
||
|
if ('function' != typeof fn) {
|
||
|
throw new TypeError('PAC file JavaScript contents must define a `FindProxyForURL` function');
|
||
|
}
|
||
|
|
||
|
// return the async resolver function
|
||
|
var resolver = co.wrap(fn);
|
||
|
|
||
|
return function FindProxyForURL (url, _host, _callback) {
|
||
|
let host
|
||
|
let callback
|
||
|
switch (arguments.length) {
|
||
|
case 3:
|
||
|
host = _host
|
||
|
callback = _callback
|
||
|
break;
|
||
|
case 2:
|
||
|
if (typeof _host === 'function') {
|
||
|
callback = _host
|
||
|
} else {
|
||
|
host = _host
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!host) {
|
||
|
host = parse(url).hostname;
|
||
|
}
|
||
|
|
||
|
const promise = resolver(url, host, callback);
|
||
|
|
||
|
if (typeof callback === 'function') {
|
||
|
toCallback(promise, callback)
|
||
|
} else {
|
||
|
return promise
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function toCallback (promise, callback) {
|
||
|
let called = false
|
||
|
function resolve(rtn) {
|
||
|
if (called) return
|
||
|
called = true
|
||
|
callback(null, rtn)
|
||
|
}
|
||
|
function reject(err) {
|
||
|
if (called) return
|
||
|
called = true
|
||
|
callback(err)
|
||
|
}
|
||
|
promise.then(resolve, reject)
|
||
|
}
|