Created
September 2, 2017 04:44
-
-
Save ericjung/77844ccda80feb5def66339dac0b1bcc to your computer and use it in GitHub Desktop.
Implementation of nsIProxyAutoConfig instead of using /netwerk/base/src/nsProxyAutoConfig.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// FoxyProxy's own nsIProxyAutoConfig impl of | |
// http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsProxyAutoConfig.cpp | |
// Why? Because Gecko's impl is a singleton. FoxyProxy needs multiple instances in order to | |
// support multiple, simultaneous PAC files (Gecko's impl cannot do this as of Moz 1.9 because | |
// of the singleon nature of this component) | |
function fpProxyAutoConfig(owner) { | |
this.owner = owner; | |
} | |
fpProxyAutoConfig.prototype = { | |
// sandbox in which we eval loaded autoconfig js file | |
sandbox : null, | |
owner: null, | |
/** throws a localized Error object on error */ | |
init: function(pacURI, pacText) { | |
let autoconfMessage = ""; | |
if (pacURI == "" || pacText == "") { | |
dump("FoxyProxy: init(), pacURI or pacText empty\n"); | |
if (this.owner && this.owner.owner) { | |
if (this.owner.owner.autoconfMode === "pac") { | |
autoconfMessage = "pac.empty"; | |
} else { | |
autoconfMessage = "wpad.empty"; | |
} | |
} else { | |
// No PAC file content found while executing |testPAC()|. Let's assume | |
// the user tested a PAC file. | |
autoconfMessage = "pac.empty"; | |
} | |
throw new Error(fp.getMessage(autoconfMessage)); | |
} | |
this.sandbox = new Components.utils.Sandbox(pacURI); | |
Components.utils.evalInSandbox(pacUtils, this.sandbox); | |
// add predefined functions to pac | |
this.sandbox.importFunction(myIpAddress); | |
this.sandbox.importFunction(dnsResolve); | |
this.sandbox.importFunction(proxyAlert, "alert"); | |
// evaluate loaded js file | |
Components.utils.evalInSandbox(pacText, this.sandbox); | |
// We can no longer trust this.sandbox. Touching it directly can | |
// cause all sorts of pain, so wrap it in an XPCSafeJSObjectWrapper | |
// and do all of our work through there. | |
this.sandbox = XPCSJSOWWrapper(this.sandbox, true); | |
// Performance improvement in FoxyProxy over Firefox | |
// by doing this next check ONCE in init() except | |
// everytime in getProxyxForURI(). | |
if (!("FindProxyForURL" in this.sandbox)) { | |
dump("FoxyProxy: init(), FindProxyForURL not found\n"); | |
if (this.owner && this.owner.owner) { | |
if (this.owner.owner.autoconfMode === "pac") { | |
autoconfMessage = "pac.fcn.notfound2"; | |
} else { | |
autoconfMessage = "wpad.fcn.notfound"; | |
} | |
} else { | |
// No FindProxyForURL in a PAC file called via |testPAC()|. Let's | |
// assume it is a PAC file. | |
autoconfMessage = "pac.fcn.notfound2"; | |
} | |
throw new Error(fp.getMessage(autoconfMessage)); | |
} | |
// We need the if-clause here as |this.owner| can be |null|. That happens | |
// if |testPAC()| is called in addeditproxy.js. | |
if (this.owner && this.owner.owner) { | |
// PAC file is ready. | |
this.owner.owner.initPAC = false; | |
} | |
return true; | |
}, | |
getProxyForURI: function(testURI, testHost) { | |
// Call the original function | |
try { | |
// Letting the PAC request through but only if we have not loaded the | |
// PAC yet. Otherwise there is no reason why the request should not use | |
// the proxy given back by the PAC. | |
if (this.owner.owner.initPAC) { | |
// Make sure we don't have a trailing slash on one of our URIs. | |
// Otherwise the comparison may fail and we risk loading the PAC file | |
// itself through the proxy if it is not initialized yet which fails | |
// for obvious reasons. | |
// See: http://forums.getfoxyproxy.org/viewtopic.php?f=4&t=816. | |
if (testURI.replace(/\/$/, '') === this.owner.url. | |
replace(/\/$/, '')) { | |
dump("FoxyProxy: Preventing cyclical PAC error; using no proxy " + | |
"to load PAC file.\n"); | |
return "direct"; | |
} | |
} | |
// This is only relevant for Gecko > 17 as the PAC logic is async now. | |
// If the PAC file is not loaded yet we return our custom error code | |
// (which is "queue" + the proxy id) to indicate that the request needs | |
// to get queued in the hooked asyncOpen(). | |
if (!fp.isGecko17 && this.owner.owner.initPAC) { | |
return "queue" + this.owner.owner.id; | |
} | |
return this.sandbox.FindProxyForURL(testURI, testHost); | |
} catch (e) { | |
dump("FoxyProxy: getProxyForURI(), " + e + " \n\n" + e.stack + "\n"); | |
throw XPCSJSOWWrapper(e); | |
} | |
} | |
} | |
/** XPCSafeJSObjectWrapper is not available before FF 3.0. Only use it if it's available. **/ | |
function XPCSJSOWWrapper(x, useNew) { | |
return typeof(XPCSafeJSObjectWrapper) == "undefined" ? | |
x : useNew ? new XPCSafeJSObjectWrapper(x) : XPCSafeJSObjectWrapper(x); | |
} | |
function proxyAlert(msg) { | |
msg = XPCSJSOWWrapper(msg); | |
try { | |
// It would appear that the console service is threadsafe. | |
var cns = Components.classes["@mozilla.org/consoleservice;1"] | |
.getService(Components.interfaces.nsIConsoleService); | |
cns.logStringMessage("PAC-alert: "+msg); | |
} catch (e) { | |
dump("PAC: proxyAlert ERROR: "+e+"\n"); | |
} | |
} | |
// wrapper for getting local IP address called by PAC file | |
function myIpAddress() { | |
try { | |
return dns.resolve(dns.myHostName, 0).getNextAddrAsString(); | |
} catch (e) { | |
return '127.0.0.1'; | |
} | |
} | |
// wrapper for resolving hostnames called by PAC file | |
function dnsResolve(host) { | |
host = XPCSJSOWWrapper(host); | |
try { | |
return dns.resolve(host, 0).getNextAddrAsString(); | |
} catch (e) { | |
return null; | |
} | |
} | |
var dns = CC["@mozilla.org/network/dns-service;1"].getService(CI.nsIDNSService); | |
var pacUtils = | |
"function dnsDomainIs(host, domain) {\n" + | |
" return (host.length >= domain.length &&\n" + | |
" host.substring(host.length - domain.length) == domain);\n" + | |
"}\n" + | |
"function dnsDomainLevels(host) {\n" + | |
" return host.split('.').length-1;\n" + | |
"}\n" + | |
"function convert_addr(ipchars) {\n"+ | |
" var bytes = ipchars.split('.');\n"+ | |
" var result = ((bytes[0] & 0xff) << 24) |\n"+ | |
" ((bytes[1] & 0xff) << 16) |\n"+ | |
" ((bytes[2] & 0xff) << 8) |\n"+ | |
" (bytes[3] & 0xff);\n"+ | |
" return result;\n"+ | |
"}\n"+ | |
"function isInNet(ipaddr, pattern, maskstr) {\n"+ | |
" var test = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ipaddr);\n"+ | |
" if (test == null) {\n"+ | |
" ipaddr = dnsResolve(ipaddr);\n"+ | |
" if (ipaddr == null)\n"+ | |
" return false;\n"+ | |
" } else if (test[1] > 255 || test[2] > 255 || \n"+ | |
" test[3] > 255 || test[4] > 255) {\n"+ | |
" return false; // not an IP address\n"+ | |
" }\n"+ | |
" var host = convert_addr(ipaddr);\n"+ | |
" var pat = convert_addr(pattern);\n"+ | |
" var mask = convert_addr(maskstr);\n"+ | |
" return ((host & mask) == (pat & mask));\n"+ | |
" \n"+ | |
"}\n"+ | |
"function isPlainHostName(host) {\n" + | |
" return (host.search('\\\\.') == -1);\n" + | |
"}\n" + | |
"function isResolvable(host) {\n" + | |
" var ip = dnsResolve(host);\n" + | |
" return (ip != null);\n" + | |
"}\n" + | |
"function localHostOrDomainIs(host, hostdom) {\n" + | |
" return (host == hostdom) ||\n" + | |
" (hostdom.lastIndexOf(host + '.', 0) == 0);\n" + | |
"}\n" + | |
"function shExpMatch(url, pattern) {\n" + | |
" pattern = pattern.replace(/\\./g, '\\\\.');\n" + | |
" pattern = pattern.replace(/\\*/g, '.*');\n" + | |
" pattern = pattern.replace(/\\?/g, '.');\n" + | |
" var newRe = new RegExp('^'+pattern+'$');\n" + | |
" return newRe.test(url);\n" + | |
"}\n" + | |
"var wdays = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};\n" + | |
"var months = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};\n"+ | |
"function weekdayRange() {\n" + | |
" function getDay(weekday) {\n" + | |
" if (weekday in wdays) {\n" + | |
" return wdays[weekday];\n" + | |
" }\n" + | |
" return -1;\n" + | |
" }\n" + | |
" var date = new Date();\n" + | |
" var argc = arguments.length;\n" + | |
" var wday;\n" + | |
" if (argc < 1)\n" + | |
" return false;\n" + | |
" if (arguments[argc - 1] == 'GMT') {\n" + | |
" argc--;\n" + | |
" wday = date.getUTCDay();\n" + | |
" } else {\n" + | |
" wday = date.getDay();\n" + | |
" }\n" + | |
" var wd1 = getDay(arguments[0]);\n" + | |
" var wd2 = (argc == 2) ? getDay(arguments[1]) : wd1;\n" + | |
" return (wd1 == -1 || wd2 == -1) ? false\n" + | |
" : (wd1 <= wday && wday <= wd2);\n" + | |
"}\n" + | |
"function dateRange() {\n" + | |
" function getMonth(name) {\n" + | |
" if (name in months) {\n" + | |
" return months[name];\n" + | |
" }\n" + | |
" return -1;\n" + | |
" }\n" + | |
" var date = new Date();\n" + | |
" var argc = arguments.length;\n" + | |
" if (argc < 1) {\n" + | |
" return false;\n" + | |
" }\n" + | |
" var isGMT = (arguments[argc - 1] == 'GMT');\n" + | |
"\n" + | |
" if (isGMT) {\n" + | |
" argc--;\n" + | |
" }\n" + | |
" // function will work even without explict handling of this case\n" + | |
" if (argc == 1) {\n" + | |
" var tmp = parseInt(arguments[0]);\n" + | |
" if (isNaN(tmp)) {\n" + | |
" return ((isGMT ? date.getUTCMonth() : date.getMonth()) ==\n" + | |
"getMonth(arguments[0]));\n" + | |
" } else if (tmp < 32) {\n" + | |
" return ((isGMT ? date.getUTCDate() : date.getDate()) == tmp);\n" + | |
" } else { \n" + | |
" return ((isGMT ? date.getUTCFullYear() : date.getFullYear()) ==\n" + | |
"tmp);\n" + | |
" }\n" + | |
" }\n" + | |
" var year = date.getFullYear();\n" + | |
" var date1, date2;\n" + | |
" date1 = new Date(year, 0, 1, 0, 0, 0);\n" + | |
" date2 = new Date(year, 11, 31, 23, 59, 59);\n" + | |
" var adjustMonth = false;\n" + | |
" for (var i = 0; i < (argc >> 1); i++) {\n" + | |
" var tmp = parseInt(arguments[i]);\n" + | |
" if (isNaN(tmp)) {\n" + | |
" var mon = getMonth(arguments[i]);\n" + | |
" date1.setMonth(mon);\n" + | |
" } else if (tmp < 32) {\n" + | |
" adjustMonth = (argc <= 2);\n" + | |
" date1.setDate(tmp);\n" + | |
" } else {\n" + | |
" date1.setFullYear(tmp);\n" + | |
" }\n" + | |
" }\n" + | |
" for (var i = (argc >> 1); i < argc; i++) {\n" + | |
" var tmp = parseInt(arguments[i]);\n" + | |
" if (isNaN(tmp)) {\n" + | |
" var mon = getMonth(arguments[i]);\n" + | |
" date2.setMonth(mon);\n" + | |
" } else if (tmp < 32) {\n" + | |
" date2.setDate(tmp);\n" + | |
" } else {\n" + | |
" date2.setFullYear(tmp);\n" + | |
" }\n" + | |
" }\n" + | |
" if (adjustMonth) {\n" + | |
" date1.setMonth(date.getMonth());\n" + | |
" date2.setMonth(date.getMonth());\n" + | |
" }\n" + | |
" if (isGMT) {\n" + | |
" var tmp = date;\n" + | |
" tmp.setFullYear(date.getUTCFullYear());\n" + | |
" tmp.setMonth(date.getUTCMonth());\n" + | |
" tmp.setDate(date.getUTCDate());\n" + | |
" tmp.setHours(date.getUTCHours());\n" + | |
" tmp.setMinutes(date.getUTCMinutes());\n" + | |
" tmp.setSeconds(date.getUTCSeconds());\n" + | |
" date = tmp;\n" + | |
" }\n" + | |
" return ((date1 <= date) && (date <= date2));\n" + | |
"}\n" + | |
"function timeRange() {\n" + | |
" var argc = arguments.length;\n" + | |
" var date = new Date();\n" + | |
" var isGMT= false;\n"+ | |
"\n" + | |
" if (argc < 1) {\n" + | |
" return false;\n" + | |
" }\n" + | |
" if (arguments[argc - 1] == 'GMT') {\n" + | |
" isGMT = true;\n" + | |
" argc--;\n" + | |
" }\n" + | |
"\n" + | |
" var hour = isGMT ? date.getUTCHours() : date.getHours();\n" + | |
" var date1, date2;\n" + | |
" date1 = new Date();\n" + | |
" date2 = new Date();\n" + | |
"\n" + | |
" if (argc == 1) {\n" + | |
" return (hour == arguments[0]);\n" + | |
" } else if (argc == 2) {\n" + | |
" return ((arguments[0] <= hour) && (hour <= arguments[1]));\n" + | |
" } else {\n" + | |
" switch (argc) {\n" + | |
" case 6:\n" + | |
" date1.setSeconds(arguments[2]);\n" + | |
" date2.setSeconds(arguments[5]);\n" + | |
" case 4:\n" + | |
" var middle = argc >> 1;\n" + | |
" date1.setHours(arguments[0]);\n" + | |
" date1.setMinutes(arguments[1]);\n" + | |
" date2.setHours(arguments[middle]);\n" + | |
" date2.setMinutes(arguments[middle + 1]);\n" + | |
" if (middle == 2) {\n" + | |
" date2.setSeconds(59);\n" + | |
" }\n" + | |
" break;\n" + | |
" default:\n" + | |
" throw 'timeRange: bad number of arguments'\n" + | |
" }\n" + | |
" }\n" + | |
"\n" + | |
" if (isGMT) {\n" + | |
" date.setFullYear(date.getUTCFullYear());\n" + | |
" date.setMonth(date.getUTCMonth());\n" + | |
" date.setDate(date.getUTCDate());\n" + | |
" date.setHours(date.getUTCHours());\n" + | |
" date.setMinutes(date.getUTCMinutes());\n" + | |
" date.setSeconds(date.getUTCSeconds());\n" + | |
" }\n" + | |
" return ((date1 <= date) && (date <= date2));\n" + | |
"}\n" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment