Bug 839120 - Support SafeBrowsing in b2g r=gpascutto
authorYusuke Yamamoto <yu-yamamoto@kddi-tech.com>
Thu, 12 Feb 2015 23:58:15 -0800
changeset 228766 76c0924aea88f0d498fc9c50d84a22cb3f106d29
parent 228765 b6df2135b0ecab0025bf088956806f5707cdf377
child 228767 e0092755a03f41118971b21f72d178d5fbbed1bd
push id13879
push userfdesre@mozilla.com
push dateFri, 13 Feb 2015 08:27:42 +0000
treeherderb2g-inbound@76c0924aea88 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgpascutto
bugs839120
milestone38.0a1
Bug 839120 - Support SafeBrowsing in b2g r=gpascutto
b2g/app/b2g.js
b2g/chrome/content/shell.js
b2g/confvars.sh
toolkit/components/url-classifier/Classifier.cpp
toolkit/components/url-classifier/content/listmanager.js
toolkit/components/url-classifier/content/moz/alarm.js
toolkit/components/url-classifier/content/moz/cryptohasher.js
toolkit/components/url-classifier/content/moz/debug.js
toolkit/components/url-classifier/content/moz/lang.js
toolkit/components/url-classifier/content/moz/observer.js
toolkit/components/url-classifier/content/moz/preferences.js
toolkit/components/url-classifier/content/moz/protocol4.js
toolkit/components/url-classifier/content/multi-querier.js
toolkit/components/url-classifier/content/request-backoff.js
toolkit/components/url-classifier/content/trtable.js
toolkit/components/url-classifier/content/wireformat.js
toolkit/components/url-classifier/content/xml-fetcher.js
toolkit/components/url-classifier/nsUrlClassifierListManager.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -335,20 +335,36 @@ pref("image.onload.decode.limit", 24); /
 // we don't really have a better one at the moment.
 // enable touch events interfaces
 pref("dom.w3c_touch_events.enabled", 1);
 pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240"
 pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240"
 
 #ifdef MOZ_SAFE_BROWSING
 // Safe browsing does nothing unless this pref is set
-pref("browser.safebrowsing.enabled", true);
+pref("browser.safebrowsing.enabled", false);
 
 // Prevent loading of pages identified as malware
-pref("browser.safebrowsing.malware.enabled", true);
+pref("browser.safebrowsing.malware.enabled", false);
+
+pref("browser.safebrowsing.debug", false);
+pref("browser.safebrowsing.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
+pref("browser.safebrowsing.reportURL", "https://safebrowsing.google.com/safebrowsing/report?");
+pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
+pref("browser.safebrowsing.appRepURL", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
+
+pref("browser.safebrowsing.id", "Firefox");
+
+// Tables for application reputation.
+pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
 
 // Non-enhanced mode (local url lists) URL list to check for updates
 pref("browser.safebrowsing.provider.0.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client={moz:client}&appver={moz:version}&pver=2.2&key=%GOOGLE_API_KEY%");
 
 pref("browser.safebrowsing.dataProvider", 0);
 
 // Does the provider name need to be localizable?
 pref("browser.safebrowsing.provider.0.name", "Google");
@@ -359,20 +375,16 @@ pref("browser.safebrowsing.provider.0.ge
 pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
 
 // FAQ URLs
 
-// Name of the about: page contributed by safebrowsing to handle display of error
-// pages on phishing/malware hits.  (bug 399233)
-pref("urlclassifier.alternate_error_page", "blocked");
-
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
 
 // Gethash timeout for Safebrowsing.
 pref("urlclassifier.gethash.timeout_ms", 5000);
 
 // If an urlclassifier table has not been updated in this number of seconds,
 // a gethash request will be forced to check that the result is still in
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -65,16 +65,21 @@ XPCOMUtils.defineLazyGetter(this, "libcu
 #endif
 
 #ifdef MOZ_CAPTIVEDETECT
 XPCOMUtils.defineLazyServiceGetter(Services, 'captivePortalDetector',
                                   '@mozilla.org/toolkit/captive-detector;1',
                                   'nsICaptivePortalDetector');
 #endif
 
+#ifdef MOZ_SAFE_BROWSING
+XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
+              "resource://gre/modules/SafeBrowsing.jsm");
+#endif
+
 function getContentWindow() {
   return shell.contentBrowser.contentWindow;
 }
 
 function debug(str) {
   dump(' -*- Shell.js: ' + str + '\n');
 }
 
@@ -357,16 +362,21 @@ var shell = {
     this.contentBrowser.src = homeURL;
     this.isHomeLoaded = false;
 
     ppmm.addMessageListener("content-handler", this);
     ppmm.addMessageListener("dial-handler", this);
     ppmm.addMessageListener("sms-handler", this);
     ppmm.addMessageListener("mail-handler", this);
     ppmm.addMessageListener("file-picker", this);
+#ifdef MOZ_SAFE_BROWSING
+    setTimeout(function() {
+      SafeBrowsing.init();
+    }, 5000);
+#endif
   },
 
   stop: function shell_stop() {
     window.removeEventListener('unload', this);
     window.removeEventListener('keydown', this, true);
     window.removeEventListener('keyup', this, true);
     window.removeEventListener('MozApplicationManifest', this);
     window.removeEventListener('mozfullscreenchange', this);
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -12,17 +12,17 @@ MOZ_UA_OS_AGNOSTIC=1
 
 MOZ_B2G_VERSION=3.0.0.0-prerelease
 MOZ_B2G_OS_NAME=Boot2Gecko
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
-MOZ_SAFE_BROWSING=
+MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_METRICS=1
 MOZ_CAPTIVEDETECT=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_NO_SMART_CARDS=1
 MOZ_APP_STATIC_INI=1
 NSS_NO_LIBPKIX=1
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -394,17 +394,18 @@ nsresult
 Classifier::RegenActiveTables()
 {
   mActiveTablesCache.Clear();
 
   nsTArray<nsCString> foundTables;
   ScanStoreDir(foundTables);
 
   for (uint32_t i = 0; i < foundTables.Length(); i++) {
-    HashStore store(nsCString(foundTables[i]), mStoreDirectory);
+    nsCString table(foundTables[i]);
+    HashStore store(table, mStoreDirectory);
 
     nsresult rv = store.Open();
     if (NS_FAILED(rv))
       continue;
 
     LookupCache *lookupCache = GetLookupCache(store.TableName());
     if (!lookupCache) {
       continue;
--- a/toolkit/components/url-classifier/content/listmanager.js
+++ b/toolkit/components/url-classifier/content/listmanager.js
@@ -11,44 +11,44 @@ Cu.import("resource://gre/modules/Servic
 // update, and store lists.
 //
 // There is a single listmanager for the whole application.
 //
 // TODO more comprehensive update tests, for example add unittest check 
 //      that the listmanagers tables are properly written on updates
 
 // Log only if browser.safebrowsing.debug is true
-function log(...stuff) {
+this.log = function log(...stuff) {
   var prefs_ = new G_Preferences();
   var debug = prefs_.getPref("browser.safebrowsing.debug");
   if (!debug) {
     return;
   }
 
   var d = new Date();
   let msg = "listmanager: " + d.toTimeString() + ": " + stuff.join(" ");
   Services.console.logStringMessage(msg);
   dump(msg + "\n");
 }
 
-function QueryAdapter(callback) {
+this.QueryAdapter = function QueryAdapter(callback) {
   this.callback_ = callback;
 };
 
 QueryAdapter.prototype.handleResponse = function(value) {
   this.callback_.handleEvent(value);
 }
 
 /**
  * A ListManager keeps track of black and white lists and knows
  * how to update them.
  *
  * @constructor
  */
-function PROT_ListManager() {
+this.PROT_ListManager = function PROT_ListManager() {
   log("Initializing list manager");
   this.prefs_ = new G_Preferences();
   this.updateInterval = this.prefs_.getPref("urlclassifier.updateinterval", 30 * 60) * 1000;
 
   // A map of tableNames to objects of type
   // { updateUrl: <updateUrl>, gethashUrl: <gethashUrl> }
   this.tablesData = {};
   // A map of updateUrls to maps of tables requiring updates, e.g.
--- a/toolkit/components/url-classifier/content/moz/alarm.js
+++ b/toolkit/components/url-classifier/content/moz/alarm.js
@@ -34,16 +34,17 @@
  *
  * @param callback Function to call when the alarm fires
  * @param delayMS Number indicating the length of the alarm period in ms
  * @param opt_repeating Boolean indicating whether this should fire 
  *                      periodically
  * @param opt_maxTimes Number indicating a maximum number of times to 
  *                     repeat (obviously only useful when opt_repeating==true)
  */
+this.G_Alarm =
 function G_Alarm(callback, delayMS, opt_repeating, opt_maxTimes) {
   this.debugZone = "alarm";
   this.callback_ = callback;
   this.repeating_ = !!opt_repeating;
   this.timer_ = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   var type = opt_repeating ? 
              this.timer_.TYPE_REPEATING_SLACK : 
              this.timer_.TYPE_ONE_SHOT;
@@ -119,21 +120,29 @@ G_Alarm.prototype.QueryInterface = funct
 
 
 /**
  * An alarm with the additional property that it cancels itself if its 
  * callback returns true.
  *
  * For parameter documentation, see G_Alarm
  */
+this.G_ConditionalAlarm =
 function G_ConditionalAlarm(callback, delayMS, opt_repeating, opt_maxTimes) {
   G_Alarm.call(this, callback, delayMS, opt_repeating, opt_maxTimes);
   this.debugZone = "conditionalalarm";
 }
 
+G_ConditionalAlarm.inherits = function(parentCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = parentCtor.prototype;
+  this.superClass_ = parentCtor.prototype;
+  this.prototype = new tempCtor();
+}
+
 G_ConditionalAlarm.inherits(G_Alarm);
 
 /**
  * Invoked by the timer when it fires
  * 
  * @param timer Reference to the nsITimer which fired (not currently 
  *              passed along)
  */
--- a/toolkit/components/url-classifier/content/moz/cryptohasher.js
+++ b/toolkit/components/url-classifier/content/moz/cryptohasher.js
@@ -15,16 +15,17 @@
 //
 // IMPORTANT NOTE: Due to https://bugzilla.mozilla.org/show_bug.cgi?id=321024
 // you cannot use the cryptohasher before app-startup. The symptom of doing
 // so is a segfault in NSS.
 
 /**
  * Instantiate a new hasher. You must explicitly call init() before use!
  */
+this.G_CryptoHasher =
 function G_CryptoHasher() {
   this.debugZone = "cryptohasher";
   this.hasher_ = null;
 }
 
 G_CryptoHasher.algorithms = {
   MD2: Ci.nsICryptoHash.MD2,
   MD5: Ci.nsICryptoHash.MD5,
@@ -141,17 +142,17 @@ G_CryptoHasher.prototype.toHex_ = functi
   }
   return hexrep.join('');
 }
 
 #ifdef DEBUG
 /**
  * Lame unittest function
  */
-function TEST_G_CryptoHasher() {
+this.TEST_G_CryptoHasher = function TEST_G_CryptoHasher() {
   if (G_GDEBUG) {
     var z = "cryptohasher UNITTEST";
     G_debugService.enableZone(z);
 
     G_Debug(z, "Starting");
 
     var md5 = function(str) {
       var hasher = new G_CryptoHasher();
--- a/toolkit/components/url-classifier/content/moz/debug.js
+++ b/toolkit/components/url-classifier/content/moz/debug.js
@@ -73,26 +73,26 @@ if (typeof G_GDEBUG == "undefined") {
 
 /**
  * Write out a debugging message.
  *
  * @param who The thingy to convert into a zone name corresponding to the 
  *            zone to which this message belongs
  * @param msg Message to output
  */
-function G_Debug(who, msg) {
+this.G_Debug = function G_Debug(who, msg) {
   if (G_GDEBUG) {
     G_GetDebugZone(who).debug(msg);
   }
 }
 
 /**
  * Debugs loudly
  */
-function G_DebugL(who, msg) {
+this.G_DebugL = function G_DebugL(who, msg) {
   if (G_GDEBUG) {
     var zone = G_GetDebugZone(who);
 
     if (zone.zoneIsEnabled()) {
       G_debugService.dump(
         "\n************************************************************\n");
 
       G_Debug(who, msg);
@@ -105,60 +105,60 @@ function G_DebugL(who, msg) {
 
 /**
  * Write out a call tracing message
  *
  * @param who The thingy to convert into a zone name corresponding to the 
  *            zone to which this message belongs
  * @param msg Message to output
  */
-function G_TraceCall(who, msg) {
+this.G_TraceCall = function G_TraceCall(who, msg) {
   if (G_GDEBUG) {
     if (G_debugService.callTracingEnabled()) {
       G_debugService.dump(msg + "\n");
     }
   }
 }
 
 /**
  * Write out an error (and throw)
  *
  * @param who The thingy to convert into a zone name corresponding to the 
  *            zone to which this message belongs
  * @param msg Message to output
  */
-function G_Error(who, msg) {
+this.G_Error = function G_Error(who, msg) {
   if (G_GDEBUG) {
     G_GetDebugZone(who).error(msg);
   }
 }
 
 /**
  * Assert something as true and signal an error if it's not
  *
  * @param who The thingy to convert into a zone name corresponding to the 
  *            zone to which this message belongs
  * @param condition Boolean condition to test
  * @param msg Message to output
  */
-function G_Assert(who, condition, msg) {
+this.G_Assert = function G_Assert(who, condition, msg) {
   if (G_GDEBUG) {
     G_GetDebugZone(who).assert(condition, msg);
   }
 }
 
 /**
  * Helper function that takes input and returns the DebugZone
  * corresponding to it.
  *
  * @param who Arbitrary input that will be converted into a zone name. Most
  *            likely an object that has .debugZone property, or a string.
  * @returns The DebugZone object corresponding to the input
  */
-function G_GetDebugZone(who) {
+this.G_GetDebugZone = function G_GetDebugZone(who) {
   if (G_GDEBUG) {
     var zone = "?";
 
     if (who && who.debugZone) {
       zone = who.debugZone;
     } else if (typeof who == "string") {
       zone = who;
     }
@@ -179,17 +179,17 @@ function G_GetDebugZone(who) {
  *
  * @constructor
  * @param service Reference to the DebugService object we use for 
  *                registration
  * @param prefix String indicating the unique prefix we should use
  *               when creating preferences to control this zone
  * @param zone String indicating the name of the zone
  */
-function G_DebugZone(service, prefix, zone) {
+this.G_DebugZone = function G_DebugZone(service, prefix, zone) {
   if (G_GDEBUG) {
     this.debugService_ = service;
     this.prefix_ = prefix;
     this.zone_ = zone;
     this.zoneEnabledPrefName_ = prefix + ".zone." + this.zone_;
     this.settings_ = new G_DebugSettings();
   }
 }
@@ -272,17 +272,17 @@ G_DebugZone.prototype.assert = function(
  * The debug service handles auto-registration of zones, namespacing
  * the zones preferences, and various global settings such as whether
  * all zones are enabled.
  *
  * @constructor
  * @param opt_prefix Optional string indicating the unique prefix we should 
  *                   use when creating preferences
  */
-function G_DebugService(opt_prefix) {
+this.G_DebugService = function G_DebugService(opt_prefix) {
   if (G_GDEBUG) {
     this.prefix_ = opt_prefix ? opt_prefix : "safebrowsing-debug-service";
     this.consoleEnabledPrefName_ = this.prefix_ + ".alsologtoconsole";
     this.allZonesEnabledPrefName_ = this.prefix_ + ".enableallzones";
     this.callTracingEnabledPrefName_ = this.prefix_ + ".trace-function-calls";
     this.logFileEnabledPrefName_ = this.prefix_ + ".logfileenabled";
     this.logFileErrorLevelPrefName_ = this.prefix_ + ".logfile-errorlevel";
     this.zones_ = {};
@@ -623,17 +623,17 @@ G_DebugService.prototype.reportScriptErr
  * This code is mostly stolen from Aaron Boodman's original
  * implementation in clobber utils.
  *
  * Note that this class uses the "loggifier" debug zone, so you'll see 
  * a complete call trace when that zone is enabled.
  *
  * @constructor
  */
-function G_Loggifier() {
+this.G_Loggifier = function G_Loggifier() {
   if (G_GDEBUG) {
     // Careful not to loggify ourselves!
     this.mark_(this);  
   }
 }
 
 /**
  * Marks an object as having been loggified. Loggification is not 
@@ -790,17 +790,17 @@ G_Loggifier.prototype.loggify = function
  * Simple abstraction around debug settings. The thing with debug settings is
  * that we want to be able to specify a default in the application's startup,
  * but have that default be overridable by the user via their prefs.
  *
  * To generalize this, we package up a dictionary of defaults with the 
  * preferences tree. If a setting isn't in the preferences tree, then we grab it
  * from the defaults.
  */
-function G_DebugSettings() {
+this.G_DebugSettings = function G_DebugSettings() {
   this.defaults_ = {};
   this.prefs_ = new G_Preferences();
 }
 
 /**
  * Returns the value of a settings, optionally defaulting to a given value if it
  * doesn't exist. If no default is specified, the default is |undefined|.
  */
@@ -830,14 +830,14 @@ if (G_GDEBUG) {
   G_debugService.enableAllZones();
 }
 
 #else
 
 // Stubs for the debugging aids scattered through this component.
 // They will be expanded if you compile yourself a debug build.
 
-function G_Debug(who, msg) { }
-function G_Assert(who, condition, msg) { }
-function G_Error(who, msg) { }
-var G_debugService = { __noSuchMethod__: function() { } };
+this.G_Debug = function G_Debug(who, msg) { }
+this.G_Assert = function G_Assert(who, condition, msg) { }
+this.G_Error = function G_Error(who, msg) { }
+this.G_debugService = { __noSuchMethod__: function() { } };
 
 #endif
--- a/toolkit/components/url-classifier/content/moz/lang.js
+++ b/toolkit/components/url-classifier/content/moz/lang.js
@@ -22,17 +22,17 @@
  * @param fn {string} Reference to the function to be bound
  *
  * @param self {object} Specifies the object which |this| should point to
  * when the function is run. If the value is null or undefined, it will default
  * to the global object.
  *
  * @returns {function} A partially-applied form of the speficied function.
  */
-function BindToObject(fn, self, opt_args) {
+this.BindToObject = function BindToObject(fn, self, opt_args) {
   var boundargs = fn.boundArgs_ || [];
   boundargs = boundargs.concat(Array.slice(arguments, 2, arguments.length));
 
   if (fn.boundSelf_)
     self = fn.boundSelf_;
   if (fn.boundFn_)
     fn = fn.boundFn_;
 
--- a/toolkit/components/url-classifier/content/moz/observer.js
+++ b/toolkit/components/url-classifier/content/moz/observer.js
@@ -26,17 +26,17 @@
  *
  * @param topic String containing the topic the observer will filter for
  *
  * @param observeFunction Reference to the function to call when the 
  *                        observer fires
  *
  * @constructor
  */
-function G_ObserverWrapper(topic, observeFunction) {
+this.G_ObserverWrapper = function G_ObserverWrapper(topic, observeFunction) {
   this.debugZone = "observer";
   this.topic_ = topic;
   this.observeFunction_ = observeFunction;
 }
 
 /**
  * XPCOM
  */
@@ -65,16 +65,17 @@ G_ObserverWrapper.prototype.observe = fu
  * @param observeFunction Reference to the function to call when the 
  *                        observer fires
  *
  * @param opt_onlyOnce Boolean indicating if the observer should unregister
  *                     after it has fired
  *
  * @constructor
  */
+this.G_ObserverServiceObserver =
 function G_ObserverServiceObserver(topic, observeFunction, opt_onlyOnce) {
   this.debugZone = "observerserviceobserver";
   this.topic_ = topic;
   this.observeFunction_ = observeFunction;
   this.onlyOnce_ = !!opt_onlyOnce;
   
   this.observer_ = new G_ObserverWrapper(this.topic_, 
                                          BindToObject(this.observe_, this));
@@ -96,17 +97,17 @@ G_ObserverServiceObserver.prototype.unre
  */
 G_ObserverServiceObserver.prototype.observe_ = function(subject, topic, data) {
   this.observeFunction_(subject, topic, data);
   if (this.onlyOnce_)
     this.unregister();
 }
 
 #ifdef DEBUG
-function TEST_G_Observer() {
+this.TEST_G_Observer = function TEST_G_Observer() {
   if (G_GDEBUG) {
 
     var z = "observer UNITTEST";
     G_debugService.enableZone(z);
 
     G_Debug(z, "Starting");
 
     var regularObserverRan = 0;
--- a/toolkit/components/url-classifier/content/moz/preferences.js
+++ b/toolkit/components/url-classifier/content/moz/preferences.js
@@ -41,16 +41,17 @@
  * @param opt_startPoint        A starting point on the prefs tree to resolve 
  *                              names passed to setPref and getPref.
  *
  * @param opt_useDefaultPranch  Set to true to work against the default 
  *                              preferences tree instead of the profile one.
  *
  * @constructor
  */
+this.G_Preferences =
 function G_Preferences(opt_startPoint, opt_getDefaultBranch) {
   this.debugZone = "prefs";
   this.observers_ = {};
   this.getDefaultBranch_ = !!opt_getDefaultBranch;
 
   this.startPoint_ = opt_startPoint || null;
 }
 
@@ -191,16 +192,17 @@ G_Preferences.prototype.removeAllObserve
 
 /**
  * Helper class that knows how to observe preference changes and
  * invoke a callback when they do
  *
  * @constructor
  * @param callback Function to call when the preference changes
  */
+this.G_PreferenceObserver =
 function G_PreferenceObserver(callback) {
   this.debugZone = "prefobserver";
   this.callback_ = callback;
 }
 
 /**
  * Invoked by the pref system when a preference changes. Passes the
  * message along to the callback.
@@ -226,17 +228,17 @@ G_PreferenceObserver.prototype.QueryInte
       iid.equals(Ci.nsIObserver) ||
       iid.equals(Ci.nsISupportsWeakReference))
     return this;
   throw Components.results.NS_ERROR_NO_INTERFACE;
 }
 
 #ifdef DEBUG
 // UNITTESTS
-function TEST_G_Preferences() {
+this.TEST_G_Preferences = function TEST_G_Preferences() {
   if (G_GDEBUG) {
     var z = "preferences UNITTEST";
     G_debugService.enableZone(z);
     G_Debug(z, "Starting");
 
     var p = new G_Preferences();
     
     var testPref = "test-preferences-unittest";
--- a/toolkit/components/url-classifier/content/moz/protocol4.js
+++ b/toolkit/components/url-classifier/content/moz/protocol4.js
@@ -16,17 +16,17 @@
 
 
 /**
  * This class knows how to serialize/deserialize maps to/from their
  * protocol4 representation.
  *
  * @constructor
  */
-function G_Protocol4Parser() {
+this.G_Protocol4Parser = function G_Protocol4Parser() {
   this.debugZone = "protocol4";
 
   this.protocol4RegExp_ = new RegExp("([^:]+):\\d+:(.*)$");
   this.newlineRegExp_ = new RegExp("(\\r)?\\n");
 }
 
 /**
  * Create a map from a protocol4 string. Silently skips invalid lines.
@@ -75,17 +75,17 @@ G_Protocol4Parser.prototype.serialize = 
   
   return text;
 }
 
 #ifdef DEBUG
 /**
  * Cheesey unittests
  */
-function TEST_G_Protocol4Parser() {
+this.TEST_G_Protocol4Parser = function TEST_G_Protocol4Parser() {
   if (G_GDEBUG) {
     var z = "protocol4 UNITTEST";
     G_debugService.enableZone(z);
 
     G_Debug(z, "Starting");
 
     var p = new G_Protocol4Parser();
     
--- a/toolkit/components/url-classifier/content/multi-querier.js
+++ b/toolkit/components/url-classifier/content/multi-querier.js
@@ -10,16 +10,17 @@
  * This is an "Abstract" base class.  Subclasses need to supply
  * the condition_ method.
  *
  * @param tokens Array of strings to lookup in the db
  * @param tableName String name of the table
  * @param callback Function callback function that takes true if the condition
  *        passes.
  */
+this.MultiQuerier =
 function MultiQuerier(tokens, tableName, callback) {
   this.tokens_ = tokens;
   this.tableName_ = tableName;
   this.callback_ = callback;
   this.dbservice_ = Cc["@mozilla.org/url-classifier/dbservice;1"]
                     .getService(Ci.nsIUrlClassifierDBService);
   // We put the current token in this variable.
   this.key_ = null;
@@ -60,38 +61,54 @@ MultiQuerier.prototype.result_ = functio
 MultiQuerier.prototype.condition_ = function(value) {
   throw "MultiQuerier is an abstract base class";
 }
 
 
 /**
  * Concrete MultiQuerier that stops if the key exists in the db.
  */
+this.ExistsMultiQuerier =
 function ExistsMultiQuerier(tokens, tableName, callback) {
   MultiQuerier.call(this, tokens, tableName, callback);
   this.debugZone = "existsMultiQuerier";
 }
+
+ExistsMultiQuerier.inherits = function(parentCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = parentCtor.prototype;
+  this.superClass_ = parentCtor.prototype;
+  this.prototype = new tempCtor();
+}
 ExistsMultiQuerier.inherits(MultiQuerier);
 
 ExistsMultiQuerier.prototype.condition_ = function(value) {
   return value.length > 0;
 }
 
 
 /**
  * Concrete MultiQuerier that looks up a key, decrypts it, then
  * checks the the resulting regular expressions for a match.
  * @param tokens Array of hosts
  */
+this.EnchashMultiQuerier =
 function EnchashMultiQuerier(tokens, tableName, callback, url) {
   MultiQuerier.call(this, tokens, tableName, callback);
   this.url_ = url;
   this.enchashDecrypter_ = new PROT_EnchashDecrypter();
   this.debugZone = "enchashMultiQuerier";
 }
+
+EnchashMultiQuerier.inherits = function(parentCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = parentCtor.prototype;
+  this.superClass_ = parentCtor.prototype;
+  this.prototype = new tempCtor();
+}
 EnchashMultiQuerier.inherits(MultiQuerier);
 
 EnchashMultiQuerier.prototype.run = function() {
   if (this.tokens_.length == 0) {
     this.callback_.handleEvent(false);
     this.dbservice_ = null;
     this.callback_ = null;
     return;
--- a/toolkit/components/url-classifier/content/request-backoff.js
+++ b/toolkit/components/url-classifier/content/request-backoff.js
@@ -7,30 +7,31 @@
 // back off for TIMEOUT_INCREMENT minutes.  If we get another error
 // immediately after we restart, we double the timeout and add
 // TIMEOUT_INCREMENT minutes, etc.
 // 
 // This is similar to the logic used by the search suggestion service.
 
 // HTTP responses that count as an error.  We also include any 5xx response
 // as an error.
-const HTTP_FOUND                 = 302;
-const HTTP_SEE_OTHER             = 303;
-const HTTP_TEMPORARY_REDIRECT    = 307;
+this.HTTP_FOUND                 = 302;
+this.HTTP_SEE_OTHER             = 303;
+this.HTTP_TEMPORARY_REDIRECT    = 307;
 
 /**
  * @param maxErrors Number of times to request before backing off.
  * @param retryIncrement Time (ms) for each retry before backing off.
  * @param maxRequests Number the number of requests needed to trigger backoff
  * @param requestPeriod Number time (ms) in which maxRequests have to occur to
  *     trigger the backoff behavior (0 to disable maxRequests)
  * @param timeoutIncrement Number time (ms) the starting timeout period
  *     we double this time for consecutive errors
  * @param maxTimeout Number time (ms) maximum timeout period
  */
+this.RequestBackoff =
 function RequestBackoff(maxErrors, retryIncrement,
                         maxRequests, requestPeriod,
                         timeoutIncrement, maxTimeout) {
   this.MAX_ERRORS_ = maxErrors;
   this.RETRY_INCREMENT_ = retryIncrement;
   this.MAX_REQUESTS_ = maxRequests;
   this.REQUEST_PERIOD_ = requestPeriod;
   this.TIMEOUT_INCREMENT_ = timeoutIncrement;
--- a/toolkit/components/url-classifier/content/trtable.js
+++ b/toolkit/components/url-classifier/content/trtable.js
@@ -4,17 +4,17 @@
 
 // XXX: This should all be moved into the dbservice class so it happens
 // in the background thread.
 
 /**
  * Abstract base class for a lookup table.
  * @construction
  */
-function UrlClassifierTable() {
+this.UrlClassifierTable = function UrlClassifierTable() {
   this.debugZone = "urlclassifier-table";
   this.name = '';
   this.needsUpdate = false;
   this.enchashDecrypter_ = new PROT_EnchashDecrypter();
   this.wrappedJSObject = this;
 }
 
 UrlClassifierTable.prototype.QueryInterface = function(iid) {
@@ -29,19 +29,26 @@ UrlClassifierTable.prototype.QueryInterf
  * Subclasses need to implement this method.
  */
 UrlClassifierTable.prototype.exists = function(url, callback) {
   throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /////////////////////////////////////////////////////////////////////
 // Url table implementation
-function UrlClassifierTableUrl() {
+this.UrlClassifierTableUrl = function UrlClassifierTableUrl() {
   UrlClassifierTable.call(this);
 }
+
+UrlClassifierTableUrl.inherits = function(parentCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = parentCtor.prototype;
+  this.superClass_ = parentCtor.prototype;
+  this.prototype = new tempCtor();
+}
 UrlClassifierTableUrl.inherits(UrlClassifierTable);
 
 /**
  * Look up a URL in a URL table
  */
 UrlClassifierTableUrl.prototype.exists = function(url, callback) {
   // nsIUrlClassifierUtils.canonicalizeURL is the old way of canonicalizing a
   // URL.  Unfortunately, it doesn't normalize numeric domains so alternate IP
@@ -58,22 +65,29 @@ UrlClassifierTableUrl.prototype.exists =
   (new ExistsMultiQuerier([oldCanonicalized, canonicalized],
                           this.name,
                           callback)).run();
 }
 
 /////////////////////////////////////////////////////////////////////
 // Domain table implementation
 
-function UrlClassifierTableDomain() {
+this.UrlClassifierTableDomain = function UrlClassifierTableDomain() {
   UrlClassifierTable.call(this);
   this.debugZone = "urlclassifier-table-domain";
   this.ioService_ = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService);
 }
+
+UrlClassifierTableDomain.inherits = function(parentCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = parentCtor.prototype;
+  this.superClass_ = parentCtor.prototype;
+  this.prototype = new tempCtor();
+}
 UrlClassifierTableDomain.inherits(UrlClassifierTable);
 
 /**
  * Look up a URL in a domain table
  * We also try to lookup domain + first path component (e.g.,
  * www.mozilla.org/products).
  *
  * @returns Boolean true if the url domain is in the table
@@ -115,20 +129,27 @@ UrlClassifierTableDomain.prototype.exist
 
   // Run the possible domains against the db.
   (new ExistsMultiQuerier(possible, this.name, callback)).run();
 }
 
 /////////////////////////////////////////////////////////////////////
 // Enchash table implementation
 
-function UrlClassifierTableEnchash() {
+this.UrlClassifierTableEnchash = function UrlClassifierTableEnchash() {
   UrlClassifierTable.call(this);
   this.debugZone = "urlclassifier-table-enchash";
 }
+
+UrlClassifierTableEnchash.inherits = function(parentCtor) {
+  var tempCtor = function(){};
+  tempCtor.prototype = parentCtor.prototype;
+  this.superClass_ = parentCtor.prototype;
+  this.prototype = new tempCtor();
+}
 UrlClassifierTableEnchash.inherits(UrlClassifierTable);
 
 /**
  * Look up a URL in an enchashDB.  We try all sub domains (up to MAX_DOTS).
  */
 UrlClassifierTableEnchash.prototype.exists = function(url, callback) {
   url = this.enchashDecrypter_.getCanonicalUrl(url);
   var host = this.enchashDecrypter_.getCanonicalHost(url,
--- a/toolkit/components/url-classifier/content/wireformat.js
+++ b/toolkit/components/url-classifier/content/wireformat.js
@@ -31,16 +31,17 @@
  * [name-of-table X.Y update?]                
  * ...key/value pairs to add or delete follow...
  * <blank line ends the table>
  *
  * The X.Y is the version number and the optional "update" token means 
  * that the table is a differential from the curent table the extension
  * has. Its absence means that this is a full, new table.
  */
+this.PROT_VersionParser =
 function PROT_VersionParser(type, opt_major, opt_minor, opt_requireMac) {
   this.debugZone = "versionparser";
   this.type = type;
   this.major = 0;
   this.minor = 0;
 
   this.badHeader = false;
 
@@ -197,17 +198,17 @@ PROT_VersionParser.prototype.processOptT
       break;
     }
   }
 
   return true;
 }
 
 #ifdef DEBUG
-function TEST_PROT_WireFormat() {
+this.TEST_PROT_WireFormat = function TEST_PROT_WireFormat() {
   if (G_GDEBUG) {
     var z = "versionparser UNITTEST";
     G_Debug(z, "Starting");
 
     var vp = new PROT_VersionParser("dummy");
     G_Assert(z, vp.fromString("[foo-bar-url 1.234]"),
              "failed to parse old format");
     G_Assert(z, "foo-bar-url" == vp.type, "failed to parse type");
--- a/toolkit/components/url-classifier/content/xml-fetcher.js
+++ b/toolkit/components/url-classifier/content/xml-fetcher.js
@@ -11,17 +11,17 @@
 
 /**
  * Because we might be in a component, we can't just assume that
  * XMLHttpRequest exists. So we use this tiny factory function to wrap the
  * XPCOM version.
  *
  * @return XMLHttpRequest object
  */
-function PROT_NewXMLHttpRequest() {
+this.PROT_NewXMLHttpRequest = function PROT_NewXMLHttpRequest() {
   var Cc = Components.classes;
   var Ci = Components.interfaces;
   var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
   // Need the following so we get onerror/load/progresschange
   request.QueryInterface(Ci.nsIJSXMLHttpRequest);
   return request;
 }
@@ -32,17 +32,17 @@ function PROT_NewXMLHttpRequest() {
  * callback.
  *
  * Note, that XMLFetcher is only used for SafeBrowsing, therefore
  * we inherit from nsILoadContext, so we can use the callbacks on the
  * channel to separate the safebrowsing cookie based on a reserved
  * appId.
  * @constructor
  */
-function PROT_XMLFetcher() {
+this.PROT_XMLFetcher = function PROT_XMLFetcher() {
   this.debugZone = "xmlfetcher";
   this._request = PROT_NewXMLHttpRequest();
   // implements nsILoadContext
   this.appId = Ci.nsIScriptSecurityManager.SAFEBROWSING_APP_ID;
   this.isInBrowserElement = false;
   this.usePrivateBrowsing = false;
   this.isContent = false;
 }
--- a/toolkit/components/url-classifier/nsUrlClassifierListManager.js
+++ b/toolkit/components/url-classifier/nsUrlClassifierListManager.js
@@ -9,17 +9,22 @@ Components.utils.import("resource://gre/
 
 #include ./content/listmanager.js
 
 var modScope = this;
 function Init() {
   // Pull the library in.
   var jslib = Cc["@mozilla.org/url-classifier/jslib;1"]
               .getService().wrappedJSObject;
-  Function.prototype.inherits = jslib.Function.prototype.inherits;
+  Function.prototype.inherits = function(parentCtor) {
+    var tempCtor = function(){};
+    tempCtor.prototype = parentCtor.prototype;
+    this.superClass_ = parentCtor.prototype;
+    this.prototype = new tempCtor();
+  },
   modScope.G_Preferences = jslib.G_Preferences;
   modScope.G_PreferenceObserver = jslib.G_PreferenceObserver;
   modScope.G_ObserverServiceObserver = jslib.G_ObserverServiceObserver;
   modScope.G_Debug = jslib.G_Debug;
   modScope.G_Assert = jslib.G_Assert;
   modScope.G_debugService = jslib.G_debugService;
   modScope.G_Alarm = jslib.G_Alarm;
   modScope.BindToObject = jslib.BindToObject;