Bug 839120 - Support SafeBrowsing in b2g r=gpascutto
authorYusuke Yamamoto <yu-yamamoto@kddi-tech.com>
Thu, 12 Feb 2015 23:58:15 -0800
changeset 256116 76c0924aea88f0d498fc9c50d84a22cb3f106d29
parent 256115 b6df2135b0ecab0025bf088956806f5707cdf377
child 256117 e0092755a03f41118971b21f72d178d5fbbed1bd
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgpascutto
bugs839120
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;