diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index a5ddb078e44b..2377f0a4dc22 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -267,7 +267,7 @@ #ifdef MOZ_SAFE_BROWSING - diff --git a/browser/components/safebrowsing/content/list-warden.js b/browser/components/safebrowsing/content/list-warden.js index 453c7f1ece47..39612b2e5c30 100644 --- a/browser/components/safebrowsing/content/list-warden.js +++ b/browser/components/safebrowsing/content/list-warden.js @@ -131,109 +131,104 @@ PROT_ListWarden.prototype.registerWhiteTable = function(tableName) { return result; } -/** - * Internal method that looks up a url in a set of tables - * - * @param tables array of table names - * @param url URL to look up - * @returns Boolean indicating if the url is in one of the tables - */ -PROT_ListWarden.prototype.isURLInTables_ = function(tables, url) { - for (var i = 0; i < tables.length; ++i) { - if (this.listManager_.safeExists(tables[i], url)) - return true; - } - return false; -} - -/** - * Internal method that looks up a url in the white list. - * - * @param url URL to look up - * @returns Boolean indicating if the url is on our whitelist - */ -PROT_ListWarden.prototype.isWhiteURL_ = function(url) { - if (!this.listManager_) - return false; - - var whitelisted = this.isURLInTables_(this.whiteTables_, url); - - if (whitelisted) - G_Debug(this, "Whitelist hit: " + url); - - return whitelisted; -} - -/** - * External method that looks up a url on the whitelist, used by the - * content-analyzer. - * - * @param url The URL to check - * @returns Boolean indicating if the url is on the whitelist - */ -PROT_ListWarden.prototype.isWhiteURL = function(url) { - return this.isWhiteURL_(url); -} - -/** - * Internal method that looks up a url in the black lists. Skips the lookup if - * the URL is on our whitelist(s). - * - * @param url URL to look up - * @returns Boolean indicating if the url is on our blacklist(s) - */ -PROT_ListWarden.prototype.isBlackURL_ = function(url) { - if (!this.listManager_) - return false; - - var blacklisted = this.isURLInTables_(this.blackTables_, url); - - if (blacklisted) - G_Debug(this, "Blacklist hit: " + url); - - return blacklisted; -} - /** * Internal method that looks up a url in both the white and black lists. * * If there is conflict, the white list has precedence over the black list. * + * This is tricky because all database queries are asynchronous. So we need + * to chain together our checks against white and black tables. We use + * MultiTableQuerier (see below) to manage this. + * * @param url URL to look up - * @returns Boolean indicating if the url is phishy. + * @param evilCallback Function if the url is evil, we call this function. */ -PROT_ListWarden.prototype.isEvilURL_ = function(url) { - return !this.isWhiteURL_(url) && this.isBlackURL_(url); +PROT_ListWarden.prototype.isEvilURL_ = function(url, evilCallback) { + (new MultiTableQuerier(url, + this.whiteTables_, + this.blackTables_, + evilCallback)).run(); } -// Some unittests -// TODO something more appropriate +/** + * This class helps us query multiple tables even though each table check + * is asynchronous. It provides callbacks for each listManager lookup + * and decides whether we need to continue querying or not. After + * instantiating the method, use run() to invoke. + * + * @param url String The url to check + * @param whiteTables Array of strings with each white table name + * @param blackTables Array of strings with each black table name + * @param evilCallback Function to call if it is an evil url + */ +function MultiTableQuerier(url, whiteTables, blackTables, evilCallback) { + this.debugZone = "multitablequerier"; + this.url_ = url; -function TEST_PROT_ListWarden() { - if (G_GDEBUG) { - var z = "listwarden UNITTEST"; - G_debugService.enableZone(z); - G_Debug(z, "Starting"); + // Since we pop from whiteTables_ and blackTables_, we need to make a copy. + this.whiteTables_ = []; + this.blackTables_ = []; + for (var i = 0; i < whiteTables.length; ++i) { + this.whiteTables_.push(whiteTables[i]); + } + for (var i = 0; i < blackTables.length; ++i) { + this.blackTables_.push(blackTables[i]); + } - var threadQueue = new TH_ThreadQueue(); - var listManager = new PROT_ListManager(threadQueue, true /* testing */); - - var warden = new PROT_ListWarden(listManager); + this.evilCallback_ = evilCallback; + this.listManager_ = Cc["@mozilla.org/url-classifier/listmanager;1"] + .getService(Ci.nsIUrlListManager); +} - // Just some really simple test - G_Assert(z, warden.registerWhiteTable("test-white-domain"), - "Failed to register test-white-domain table"); - G_Assert(z, warden.registerWhiteTable("test-black-url"), - "Failed to register test-black-url table"); - listManager.safeInsert("test-white-domain", "http://foo.com/good", "1"); - listManager.safeInsert("test-black-url", "http://foo.com/good/1", "1"); - listManager.safeInsert("test-black-url", "http://foo.com/bad/1", "1"); - - G_Assert(z, !warden.isEvilURL_("http://foo.com/good/1"), - "White listing is not working."); - G_Assert(z, warden.isEvilURL_("http://foo.com/bad/1"), - "Black listing is not working."); - - G_Debug(z, "PASSED"); +/** + * We first query the white tables in succession. If any contain + * the url, we stop. If none contain the url, we query the black tables + * in succession. If any contain the url, we call evilCallback and + * stop. If none of the black tables contain the url, then we just stop + * (i.e., it's not black url). + */ +MultiTableQuerier.prototype.run = function() { + if (this.whiteTables_.length > 0) { + var tableName = this.whiteTables_.pop(); + G_Debug(this, "Looking in whitetable: " + tableName); + this.listManager_.safeExists(tableName, this.url_, + BindToObject(this.whiteTableCallback_, + this)); + } else if (this.blackTables_.length > 0) { + var tableName = this.blackTables_.pop(); + G_Debug(this, "Looking in blacktable: " + tableName); + this.listManager_.safeExists(tableName, this.url_, + BindToObject(this.blackTableCallback_, + this)); + } else { + // No tables left to check, so we quit. + G_Debug(this, "Not found in any tables: " + this.url_); + } +} + +/** + * After checking a white table, we return here. If the url is found, + * we can stop. Otherwise, we call run again. + */ +MultiTableQuerier.prototype.whiteTableCallback_ = function(isFound) { + G_Debug(this, "whiteTableCallback_: " + isFound); + if (!isFound) + this.run(); + else + G_Debug(this, "Found in whitelist: " + this.url_) +} + +/** + * After checking a black table, we return here. If the url is found, + * we can call the evilCallback and stop. Otherwise, we call run again. + */ +MultiTableQuerier.prototype.blackTableCallback_ = function(isFound) { + G_Debug(this, "blackTableCallback_: " + isFound); + if (!isFound) { + this.run(); + } else { + // In the blacklist, must be an evil url. + G_Debug(this, "Found in blacklist: " + this.url_) + this.evilCallback_(); } } diff --git a/browser/components/safebrowsing/content/phishing-warden.js b/browser/components/safebrowsing/content/phishing-warden.js index aac59387d552..caa65f194141 100644 --- a/browser/components/safebrowsing/content/phishing-warden.js +++ b/browser/components/safebrowsing/content/phishing-warden.js @@ -266,20 +266,15 @@ PROT_PhishingWarden.prototype.onDocNavStart = function(e) { // We're enabled. Either send a request off or check locally // TODO: move this logic to checkUrl, formalize the error callback if (this.checkRemote_) { - // Use local whitelists to suppress remote BL lookups. - if (!this.isWhiteURL_(url)) { - G_Debug(this, "Local whitelist lookup failed"); - this.fetcher_.get(url, - BindToObject(this.onTRFetchComplete, - this, - request)); - } else { - G_Debug(this, "WL suppressing BL lookup for " + url); - } + // TODO: Use local whitelists to suppress remote BL lookups. + this.fetcher_.get(url, + BindToObject(this.onTRFetchComplete, + this, + request)); } else { - if (this.checkUrl(url)) { - this.houstonWeHaveAProblem_(request); - } + this.checkUrl(url, BindToObject(this.houstonWeHaveAProblem_, + this, + request)); } } } @@ -432,22 +427,26 @@ PROT_PhishingWarden.prototype.isBlacklistTestURL = function(url) { /** * Look the URL up in our local blacklists * + * @param url URL to check * @param callback Function to invoke if there is a problem. * - * @param url URL to check */ -PROT_PhishingWarden.prototype.checkUrl = function(url) { +PROT_PhishingWarden.prototype.checkUrl = function(url, callback) { G_Debug(this, "Checking URL for " + url); - - if (this.isEvilURL_(url) || this.isBlacklistTestURL(url)) { - G_Debug(this, "Local blacklist hit"); - // maybe send a report - (new PROT_Reporter).report("phishblhit", url); - return true; + if (this.isBlacklistTestURL(url)) { + callback(); + } else { + // We wrap the callback because we also want + // to report the blacklist hit to our data provider. + function evilCallback() { + G_Debug("evilCallback", "Local blacklist hit"); + // maybe send a report + (new PROT_Reporter).report("phishblhit", url); + callback(); + } + // Check the local lists. + this.isEvilURL_(url, evilCallback); } - - G_Debug(this, "Local blacklist miss"); - return false; } /** diff --git a/browser/components/safebrowsing/src/safebrowsingApplication.js b/browser/components/safebrowsing/src/safebrowsingApplication.js index e3476b6ea6cf..ccd3064865f5 100644 --- a/browser/components/safebrowsing/src/safebrowsingApplication.js +++ b/browser/components/safebrowsing/src/safebrowsingApplication.js @@ -1,6 +1,6 @@ const Cc = Components.classes; const Ci = Components.interfaces; -const G_GDEBUG = true; +const G_GDEBUG = false; // Use subscript loader to load files. The files in ../content get mapped // to chrome://browser/content/safebrowsing/. Order matters if one file depends diff --git a/toolkit/components/url-classifier/content/list-warden.js b/toolkit/components/url-classifier/content/list-warden.js deleted file mode 100644 index 2be5e4d50d64..000000000000 --- a/toolkit/components/url-classifier/content/list-warden.js +++ /dev/null @@ -1,225 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Google Safe Browsing. - * - * The Initial Developer of the Original Code is Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Niels Provos (original author)d - - * Fritz Schneider - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// A warden that knows how to register lists with a listmanager and keep them -// updated if necessary. The ListWarden also provides a simple interface to -// check if a URL is evil or not. Specialized wardens like the PhishingWarden -// inherit from it. -// -// Classes that inherit from ListWarden are responsible for calling -// enableTableUpdates or disableTableUpdates. This usually entails -// registering prefObservers and calling enable or disable in the base -// class as appropriate. -// - -/** - * Abtracts the checking of user/browser actions for signs of - * phishing. - * - * @param ListManager ListManager that allows us to check against white - * and black lists. - * - * @constructor - */ -function PROT_ListWarden(listManager) { - this.debugZone = "listwarden"; - this.listManager_ = listManager; - - // Use this to query preferences - this.prefs_ = new G_Preferences(); - - // Once we register tables, their respective names will be listed here. - this.blackTables_ = []; - this.whiteTables_ = []; - this.sandboxUpdates_ = []; -} - -/** - * Tell the ListManger to keep all of our tables updated - */ - -PROT_ListWarden.prototype.enableTableUpdates = function() { - this.listManager_.enableUpdateTables(this.blackTables_); - this.listManager_.enableUpdateTables(this.whiteTables_); -} - -/** - * Tell the ListManager to stop updating our tables - */ - -PROT_ListWarden.prototype.disableTableUpdates = function() { - this.listManager_.disableUpdateTables(this.blackTables_); - this.listManager_.disableUpdateTables(this.whiteTables_); -} - -/** - * Tell the ListManager to keep sandbox updated. Don't tie this to the wl/bl - * updates. - */ -PROT_ListWarden.prototype.enableSandboxUpdates = function() { - this.listManager_.enableUpdateTables(this.sandboxUpdates_); -} - -/** - * Tell the ListManager not to keep sandbox updated. Don't tie this to the - * wl/bl updates. - */ -PROT_ListWarden.prototype.disableSandboxUpdates = function() { - this.listManager_.disableUpdateTables(this.sandboxUpdates_); -} - -/** - * Register a new black list table with the list manager - * @param tableName - name of the table to register - * @returns true if the table could be registered, false otherwise - */ - -PROT_ListWarden.prototype.registerBlackTable = function(tableName) { - var result = this.listManager_.registerTable(tableName); - if (result) - this.blackTables_.push(tableName); - return result; -} - -/** - * Register a new white list table with the list manager - * @param tableName - name of the table to register - * @returns true if the table could be registered, false otherwise - */ - -PROT_ListWarden.prototype.registerWhiteTable = function(tableName) { - var result = this.listManager_.registerTable(tableName); - if (result) - this.whiteTables_.push(tableName); - return result; -} - -/** - * Internal method that looks up a url in a set of tables - * - * @param tables array of table names - * @param url URL to look up - * @returns Boolean indicating if the url is in one of the tables - */ -PROT_ListWarden.prototype.isURLInTables_ = function(tables, url) { - for (var i = 0; i < tables.length; ++i) { - if (this.listManager_.safeLookup(tables[i], url)) - return true; - } - return false; -} - -/** - * Internal method that looks up a url in the white list. - * - * @param url URL to look up - * @returns Boolean indicating if the url is on our whitelist - */ -PROT_ListWarden.prototype.isWhiteURL_ = function(url) { - if (!this.listManager_) - return false; - - var whitelisted = this.isURLInTables_(this.whiteTables_, url); - - if (whitelisted) - G_Debug(this, "Whitelist hit: " + url); - - return whitelisted; -} - -/** - * Internal method that looks up a url in the black lists. - * - * @param url URL to look up - * @returns Boolean indicating if the url is on our blacklist(s) - */ -PROT_ListWarden.prototype.isBlackURL_ = function(url) { - if (!this.listManager_) - return false; - - var blacklisted = this.isURLInTables_(this.blackTables_, url); - - if (blacklisted) - G_Debug(this, "Blacklist hit: " + url); - - return blacklisted; -} - -/** - * Internal method that looks up a url in both the white and black lists. - * - * If there is conflict, the white list has precedence over the black list. - * - * @param url URL to look up - * @returns Boolean indicating if the url is phishy. - */ -PROT_ListWarden.prototype.isEvilURL_ = function(url) { - return !this.isWhiteURL_(url) && this.isBlackURL_(url); -} - -// Some unittests -// TODO something more appropriate - -function TEST_PROT_ListWarden() { - if (G_GDEBUG) { - var z = "listwarden UNITTEST"; - G_debugService.enableZone(z); - G_Debug(z, "Starting"); - - var threadQueue = new TH_ThreadQueue(); - var listManager = new PROT_ListManager(threadQueue, true /* testing */); - - var warden = new PROT_ListWarden(listManager); - - // Just some really simple test - G_Assert(z, warden.registerWhiteTable("test-white-domain"), - "Failed to register test-white-domain table"); - G_Assert(z, warden.registerWhiteTable("test-black-url"), - "Failed to register test-black-url table"); - listManager.safeInsert("test-white-domain", "http://foo.com/good", "1"); - listManager.safeInsert("test-black-url", "http://foo.com/good/1", "1"); - listManager.safeInsert("test-black-url", "http://foo.com/bad/1", "1"); - - G_Assert(z, !warden.isEvilURL_("http://foo.com/good/1"), - "White listing is not working."); - G_Assert(z, warden.isEvilURL_("http://foo.com/bad/1"), - "Black listing is not working."); - - G_Debug(z, "PASSED"); - } -} diff --git a/toolkit/components/url-classifier/content/listmanager.js b/toolkit/components/url-classifier/content/listmanager.js index 4368b706f4af..68965a2b320c 100644 --- a/toolkit/components/url-classifier/content/listmanager.js +++ b/toolkit/components/url-classifier/content/listmanager.js @@ -268,65 +268,21 @@ PROT_ListManager.prototype.stopUpdateChecker = function() { * use this because at certain points our tables might not be loaded, * and querying them could throw. * - * @param table Name of the table that we want to consult - * @param key Key for table lookup - * @returns false or the value in the table corresponding to key. - * If the table name does not exist, we return false, too. + * @param table String Name of the table that we want to consult + * @param key String Key for table lookup + * @param callback nsIUrlListManagerCallback (ie., Function) given false or the + * value in the table corresponding to key. If the table name does not + * exist, we return false, too. */ -PROT_ListManager.prototype.safeExists = function(table, key) { - var result = false; +PROT_ListManager.prototype.safeExists = function(table, key, callback) { try { + G_Debug(this, "safeExists: " + table + ", " + key); var map = this.tablesData[table]; - result = map.exists(key); + map.exists(key, callback); } catch(e) { - result = false; G_Debug(this, "safeExists masked failure for " + table + ", key " + key + ": " + e); + callback.handleEvent(false); } - - return result; -} - -/** - * Provides an exception free way to insert data into a table. - * @param table Name of the table that we want to consult - * @param key Key for table insert - * @param value Value for table insert - * @returns true if the value could be inserted, false otherwise - */ -PROT_ListManager.prototype.safeInsert = function(table, key, value) { - if (!this.tablesKnown_[table]) { - G_Debug(this, "Unknown table: " + table); - return false; - } - if (!this.tablesData[table]) - this.tablesData[table] = newUrlClassifierTable(table); - try { - this.tablesData[table].insert(key, value); - } catch (e) { - G_Debug(this, "Cannot insert key " + key + " value " + value); - G_Debug(this, e); - return false; - } - - return true; -} - -/** - * Provides an exception free way to remove data from a table. - * @param table Name of the table that we want to consult - * @param key Key for table erase - * @returns true if the value could be removed, false otherwise - */ -PROT_ListManager.prototype.safeRemove = function(table, key) { - if (!this.tablesKnown_[table]) { - G_Debug(this, "Unknown table: " + table); - return false; - } - - if (!this.tablesData[table]) - return false; - - return this.tablesData[table].remove(key); } /** @@ -348,43 +304,30 @@ PROT_ListManager.prototype.loadTableVersions_ = function() { } /** - * Get lines of the form "[goog-black-enchash 1.1234]" or - * "[goog-white-url 1.1234 update]" and set the version numbers in the user - * pref. - * @param updateString String containing the response from the server. - * @return Array a list of table names + * Callback from db update service. As new tables are added to the db, + * this callback is fired so we can update the version number. + * @param versionString String containing the table update response from the + * server */ -PROT_ListManager.prototype.setTableVersions_ = function(updateString) { - var updatedTables = []; +PROT_ListManager.prototype.setTableVersion_ = function(versionString) { + G_Debug(this, "Got version string: " + versionString); + var versionParser = new PROT_VersionParser(""); + if (versionParser.fromString(versionString)) { + var tableName = versionParser.type; + var versionNumber = versionParser.versionString(); + var prefBase = kTableVersionPrefPrefix; - var prefBase = kTableVersionPrefPrefix; - var startPos = updateString.indexOf('['); - var endPos; - while (startPos != -1) { - // [ needs to be the start of a new line - if (0 == startPos || ('\n' == updateString[startPos - 1] && - '\n' == updateString[startPos - 2])) { - endPos = updateString.indexOf('\n', startPos); - if (endPos != -1) { - var line = updateString.substring(startPos, endPos); - var versionParser = new PROT_VersionParser("dummy"); - - if (versionParser.fromString(line)) { - var tableName = versionParser.type; - var version = versionParser.major + '.' + versionParser.minor; - G_Debug(this, "Set table version for " + tableName + ": " + version); - this.prefs_.setPref(prefBase + tableName, version); - this.tablesKnown_[tableName].ImportVersion(versionParser); - - updatedTables.push(tableName); - } - } + this.prefs_.setPref(prefBase + tableName, versionNumber); + + if (!this.tablesKnown_[tableName]) { + this.tablesKnown_[tableName] = versionParser; + } else { + this.tablesKnown_[tableName].ImportVersion(versionParser); } - // This could catch option params, but that's ok. The double newline - // check will skip over it. - startPos = updateString.indexOf('[', startPos + 1); + + if (!this.tablesData[tableName]) + this.tablesData[tableName] = newUrlClassifierTable(tableName); } - return updatedTables; } /** @@ -485,32 +428,12 @@ PROT_ListManager.prototype.rpcDone = function(data) { return; } - // List updates (local lists) don't work yet. See bug 336203. - throw Exception("dbservice not yet implemented."); - var dbUpdateSrv = Cc["@mozilla.org/url-classifier/dbservice;1"] .getService(Ci.nsIUrlClassifierDBService); - // Update the tables on disk. - try { - dbUpdateSrv.updateTables(data); - } catch (e) { - // dbUpdateSrv will throw an error if the background thread is already - // working. In this case, we just wait for the next scheduled update. - G_Debug(this, "Skipping update, write thread busy."); - return; - } - - // While the update is being processed by a background thread, we need - // to also update the table versions. - var tableNames = this.setTableVersions_(data); - G_Debug(this, "Updated tables: " + tableNames); - - for (var t = 0, name = null; name = tableNames[t]; ++t) { - // Create the table object if it doesn't exist. - if (!this.tablesData[name]) - this.tablesData[name] = newUrlClassifierTable(name); - } + // Update the tables on disk in a background thread. Multiple updates + // will be queue up. + dbUpdateSrv.updateTables(data, BindToObject(this.setTableVersion_, this)); } /** diff --git a/toolkit/components/url-classifier/content/map.js b/toolkit/components/url-classifier/content/map.js deleted file mode 100644 index d554f110ec89..000000000000 --- a/toolkit/components/url-classifier/content/map.js +++ /dev/null @@ -1,232 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Google Safe Browsing. - * - * The Initial Developer of the Original Code is Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Fritz Schneider (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -// This is a map over which you can iterate (you can't get an iterator -// for an Object used as a map). It is important to have an iterable -// map if you have a large numbe ofkeys and you wish to process them -// in chunks, for example on a thread. -// -// This Map's operations are all O(1) plus the time of the native -// operations on its arrays and object. The tradeoff for this speed is -// that the size of the map is always non-decreasing. That is, when an -// item is remove()'d, it is merely marked as invalid and not actually -// removed. -// -// This map is not safe if your keys are objects (they'll get -// stringified to the same value in non-debug builds). -// -// Interface: -// insert(key, value) -// remove(key) -// exists(key) -// getList() // This is our poor man's iterator -// forEach(someFunc) -// replace(otherMap) // Clones otherMap, replacing the current map -// count // readonly attribute -// -// TODO: we could easily have this map periodically compact itself so as -// to eliminate the size tradeoff. - -/** - * Create a new Map - * - * @constructor - * @param opt_name A string used to name the map - */ -function G_Map(opt_name) { - this.debugZone = "map"; - this.name = "noname"; - - // We store key/value pairs sequentially in membersArray - this.membersArray_ = []; - - // In membersMap we map from keys to indices in the membersArray - this.membersMap_ = {}; - this.count_ = 0; - - // set to true to allow list manager to update - this.needsUpdate = false; -} - -/** - * Add an item - * - * @param key An key to add (overwrites previous key) - * @param value The value to store at that key - */ -G_Map.prototype.insert = function(key, value) { - if (key == null) - throw new Error("Can't use null as a key"); - else if (typeof key == "object") - throw new Error("This class is not objectsafe; use ObjectSafeMap"); - if (value === undefined) - throw new Error("Can't store undefined values in this map"); - - // Get rid of the old value, if there was one, and increment count if not - var oldIndexInArray = this.membersMap_[key]; - if (typeof oldIndexInArray == "number") - this.membersArray_[oldIndexInArray] = undefined; - else - this.count_++; - - var indexInArray = this.membersArray_.length; - this.membersArray_.push({ "key": key, "value": value}); - this.membersMap_[key] = indexInArray; -} - -/** - * Remove a key from the map - * - * @param key The key to remove - * @returns Boolean indicating if the key was removed - */ -G_Map.prototype.remove = function(key) { - var indexInArray = this.membersMap_[key]; - - if (indexInArray === undefined) - return false; - - this.count_--; - delete this.membersMap_[key]; - // We could slice here, but that could be expensive if the map large - this.membersArray_[indexInArray] = undefined; - - return true; -} - -/** - * Private lookup function - * - * @param key The key to look up - * @returns The value at that key or undefined if it doesn't exist - */ -G_Map.prototype.find_ = function(key) { - var indexInArray = this.membersMap_[key]; - return ((indexInArray === undefined) ? - undefined : - this.membersArray_[indexInArray].value); -} - -/** - * Public lookup function - * - * @param key The key to look up - * @returns The value at that key or undefined if it doesn't exist - */ -G_Map.prototype.exists = function(key) { - return this.find_(key); -} - -/** - * Return the list of the keys we have. Use findValue to get the associated - * value. - * - * TODO: its probably better to expose a real iterator, but this works - * TODO: getting keys and values is a pain, do something more clever - * - * @returns Array of items in the map, some entries of which might be - * undefined. Each item is an object with members key and - * value - */ -G_Map.prototype.getKeys = function(count) { - var ret = []; - for (var i = 0; i < this.membersArray_.length; ++i) { - ret.push(this.membersArray_[i].key); - } - count.value = ret.length; - return ret; -} - -G_Map.prototype.findValue = function(key) { - return this.find_(key); -} - -/** - * Replace one map with the content of another - * - * IMPORTANT NOTE: This method copies references to objects, it does - * NOT copy the objects themselves. - * - * @param other Reference to a G_Map that we should clone - */ -G_Map.prototype.replace = function(other) { - this.membersMap_ = {}; - this.membersArray_ = []; - - // TODO Make this faster, and possibly run it on a thread - var lst = {}; - var otherList = other.getList(lst); - for (var i = 0; i < otherList.length; i++) - if (otherList[i]) { - var index = this.membersArray_.length; - this.membersArray_.push(otherList[i]); - this.membersMap_[otherList[i].key] = index; - } - this.count_ = other.count; -} - -/** - * Apply a function to each of the key value pairs. - * - * @param func Function to apply to the map's key value pairs - */ -G_Map.prototype.forEach = function(func) { - if (typeof func != "function") - throw new Error("argument to forEach is not a function, it's a(n) " + - typeof func); - - for (var i = 0; i < this.membersArray_.length; i++) - if (this.membersArray_[i]) - func(this.membersArray_[i].key, this.membersArray_[i].value); -} - -G_Map.prototype.QueryInterface = function(iid) { - if (iid.equals(Components.interfaces.nsISupports) || - iid.equals(Components.interfaces.nsIUrlClassifierTable)) - return this; - - Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; - return null; -} - -/** - * Readonly count attribute. - * @returns The number of keys in the map - */ -G_Map.prototype.__defineGetter__('count', function() { - return this.count_; -}); diff --git a/toolkit/components/url-classifier/content/multi-querier.js b/toolkit/components/url-classifier/content/multi-querier.js new file mode 100644 index 000000000000..64ff19270200 --- /dev/null +++ b/toolkit/components/url-classifier/content/multi-querier.js @@ -0,0 +1,145 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Google Safe Browsing. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Tony Chang (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * This class helps us batch a series of async calls to the db. + * If any of the tokens is in the database, we fire callback with + * true as a param. If all the tokens are not in the database, + * we fire callback with false as a param. + * 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. + */ +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; +} + +/** + * Run the remaining tokens against the db. + */ +MultiQuerier.prototype.run = function() { + if (this.tokens_.length == 0) { + this.callback_.handleEvent(false); + return; + } + + this.key_ = this.tokens_.pop(); + G_Debug(this, "Looking up " + this.key_ + " in " + this.tableName_); + this.dbservice_.exists(this.tableName_, this.key_, + BindToObject(this.result_, this)); +} + +/** + * Callback from the db. If the returned value passes the this.condition_ + * test, go ahead and call the main callback. + */ +MultiQuerier.prototype.result_ = function(value) { + if (this.condition_(value)) + this.callback_.handleEvent(true) + else + this.run(); +} + +// Subclasses must override this. +MultiQuerier.prototype.condition_ = function(value) { + throw "MultiQuerier is an abstract base class"; +} + + +/** + * Concrete MultiQuerier that stops if the key exists in the db. + */ +function ExistsMultiQuerier(tokens, tableName, callback) { + MultiQuerier.call(this, tokens, tableName, callback); + this.debugZone = "existsMultiQuerier"; +} +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 + */ +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(MultiQuerier); + +EnchashMultiQuerier.prototype.run = function() { + if (this.tokens_.length == 0) { + this.callback_.handleEvent(false); + return; + } + var host = this.tokens_.pop(); + this.key_ = host; + var lookupKey = this.enchashDecrypter_.getLookupKey(host); + this.dbservice_.exists(this.tableName_, lookupKey, + BindToObject(this.result_, this)); +} + +EnchashMultiQuerier.prototype.condition_ = function(encryptedValue) { + if (encryptedValue.length > 0) { + // We have encrypted regular expressions for this host. Let's + // decrypt them and see if we have a match. + var decrypted = this.enchashDecrypter_.decryptData(encryptedValue, + this.key_); + var res = this.enchashDecrypter_.parseRegExps(decrypted); + for (var j = 0; j < res.length; j++) { + if (res[j].test(this.url_)) { + return true; + } + } + } + return false; +} diff --git a/toolkit/components/url-classifier/content/wireformat.js b/toolkit/components/url-classifier/content/wireformat.js index 2d064495a22c..3e5e9b2be063 100644 --- a/toolkit/components/url-classifier/content/wireformat.js +++ b/toolkit/components/url-classifier/content/wireformat.js @@ -105,25 +105,34 @@ PROT_VersionParser.prototype.ImportVersion = function(version) { this.mac = version.mac; this.macFailed = version.macFailed; this.macval = version.macval; - // Don't set requireMac, since wfr creates vparsers from scratch and doesn't + // Don't set requireMac, since we create vparsers from scratch and doesn't // know about it } /** * Creates a string like [goog-white-black 1.1] from internal information * - * @returns version string + * @returns String */ PROT_VersionParser.prototype.toString = function() { var s = "[" + this.type + " " + this.major + "." + this.minor + "]"; return s; } +/** + * Creates a string like 1.123 with the version number. This is the + * format we store in prefs. + * @return String + */ +PROT_VersionParser.prototype.versionString = function() { + return this.major + "." + this.minor; +} + /** * Creates a string like 1:1 from internal information used for * fetching updates from the server. Called by the listmanager. * - * @returns version string + * @returns String */ PROT_VersionParser.prototype.toUrl = function() { return this.major + ":" + this.minor; diff --git a/toolkit/components/url-classifier/jar.mn b/toolkit/components/url-classifier/jar.mn index 4ecdde0bd3f4..b43a34329393 100644 --- a/toolkit/components/url-classifier/jar.mn +++ b/toolkit/components/url-classifier/jar.mn @@ -2,8 +2,7 @@ toolkit.jar: + content/global/url-classifier/application.js (content/application.js) + content/global/url-classifier/enchash-decrypter.js (content/enchash-decrypter.js) + content/global/url-classifier/listmanager.js (content/listmanager.js) -+ content/global/url-classifier/list-warden.js (content/list-warden.js) -+ content/global/url-classifier/map.js (content/map.js) ++ content/global/url-classifier/multi-querier.js (content/multi-querier.js) + content/global/url-classifier/url-canonicalizer.js (content/url-canonicalizer.js) + content/global/url-classifier/url-crypto.js (content/url-crypto.js) + content/global/url-classifier/url-crypto-key-manager.js (content/url-crypto-key-manager.js) diff --git a/toolkit/components/url-classifier/public/nsIUrlClassifierTable.idl b/toolkit/components/url-classifier/public/nsIUrlClassifierTable.idl index ebd46eabe8e6..e58d5cf1b23f 100644 --- a/toolkit/components/url-classifier/public/nsIUrlClassifierTable.idl +++ b/toolkit/components/url-classifier/public/nsIUrlClassifierTable.idl @@ -36,15 +36,13 @@ * ***** END LICENSE BLOCK ***** */ #include "nsISupports.idl" +#include "nsIUrlListManager.idl" // A map that contains a string keys mapped to string values. -// TODO: maybe nsISerializeable to handle reading/writing from disk? [scriptable, uuid(fd1f8334-1859-472d-b01f-4ac6b1121ce4)] interface nsIUrlClassifierTable : nsISupports { - readonly attribute long count; - /** * The name used to identify this table */ @@ -57,27 +55,9 @@ interface nsIUrlClassifierTable : nsISupports /** * In the simple case, exists just looks up the string in the - * table and returns true if it is found. However, it could - * do something more complex (e.g., canonicalize the url). + * table and call the callback after the query returns with true or + * false. It's possible that something more complex happens + * (e.g., canonicalize the url). */ - boolean exists(in ACString key); - - /** - * In the simple case, key is a url and value is 1. However, - * value could be more complicated (e.g., hashed value based - * on site domain). - */ - void insert(in ACString key, in ACString value); - - void remove(in ACString key); - - // TEMPORARY: used to help serialize the table to disk. May be removed. - void getKeys(out unsigned long size, - [retval,array,size_is(size)] out string keys); - - // TEMPORARY: used to help serialize the table to disk. May be removed. - void findValue(in ACString key); - - // TODO: merge data - // void replace(in nsIUrlClassifierTable); + void exists(in ACString key, in nsIUrlListManagerCallback cb); }; diff --git a/toolkit/components/url-classifier/public/nsIUrlListManager.idl b/toolkit/components/url-classifier/public/nsIUrlListManager.idl index 4bc8c6258126..3d4351f4413b 100644 --- a/toolkit/components/url-classifier/public/nsIUrlListManager.idl +++ b/toolkit/components/url-classifier/public/nsIUrlListManager.idl @@ -41,16 +41,15 @@ * Interface for a class that manages updates of multiple nsIUrlClassifierTables. */ -interface nsIFile; +// Interface for JS function callbacks +[scriptable, function, uuid(ba913c5c-13d6-41eb-83c1-de2f4165a516)] +interface nsIUrlListManagerCallback : nsISupports { + void handleEvent(in boolean value); +}; [scriptable, uuid(e1a80418-1bf9-4bd7-a40d-94d549c24955)] interface nsIUrlListManager : nsISupports { - /** - * Set the directory to read/write tables to. - */ - void setAppDir(in nsIFile appDir); - /** * Add a table to the list of tables we are managing. The name is a * string of the format provider_name-semantic_type-table_type. For @@ -71,21 +70,10 @@ interface nsIUrlListManager : nsISupports void disableUpdate(in ACString tableName); /** - * Lookup a key in a table. Should not raise exceptions. Returns - * true if the key was found into the table. + * Lookup a key in a table. Should not raise exceptions. Calls + * the callback function with a single parameter: true if the key + * is in the table, false if it isn't. */ - boolean safeExists(in ACString tableName, in ACString key); - - /** - * Insert a key in a table. Should not raise exceptions. Returns - * true if the key was inserted into the table. - */ - boolean safeInsert(in ACString tableName, in ACString key, - in ACString value); - - /** - * Remove a key from a table. Should not raise exceptions. Returns - * true if the key was removed from the table. - */ - boolean safeRemove(in ACString tableName, in string key); + void safeExists(in ACString tableName, in ACString key, + in nsIUrlListManagerCallback cb); }; diff --git a/toolkit/components/url-classifier/src/Makefile.in b/toolkit/components/url-classifier/src/Makefile.in index 95da84a161cd..a63522ef98c8 100644 --- a/toolkit/components/url-classifier/src/Makefile.in +++ b/toolkit/components/url-classifier/src/Makefile.in @@ -29,7 +29,6 @@ LOCAL_INCLUDES = \ # EXTRA_COMPONENTS installs components written in JS to dist/bin/components EXTRA_COMPONENTS = urlClassifierTableUrl.js \ urlClassifierTableDomain.js \ - urlClassifierTableSite.js \ urlClassifierTableEnchash.js \ urlListManager.js \ $(NULL) diff --git a/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp index 08b609d0097f..ff7f9253c29a 100644 --- a/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/src/nsUrlClassifierDBService.cpp @@ -340,7 +340,7 @@ nsUrlClassifierDBServiceWorker::ProcessUpdateTable( nsresult rv = NS_ERROR_FAILURE; if ('+' == op && spacePos != kNotFound) { - // Insert operation of the form "+KEY VALUE" + // Insert operation of the form "+KEY\tVALUE" const nsDependentCSubstring &key = Substring(aLine, 1, spacePos - 1); const nsDependentCSubstring &value = Substring(aLine, spacePos + 1); aUpdateStatement->BindUTF8StringParameter(0, key); diff --git a/toolkit/components/url-classifier/src/urlClassifierTableDomain.js b/toolkit/components/url-classifier/src/urlClassifierTableDomain.js index 7ec723f528b0..69b60286803b 100644 --- a/toolkit/components/url-classifier/src/urlClassifierTableDomain.js +++ b/toolkit/components/url-classifier/src/urlClassifierTableDomain.js @@ -1,3 +1,43 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Tony Chang + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// TODO: Combine this file with other urlClassifierTable files and rename to +// nsUrlClassifierTable.js + const Cc = Components.classes; const Ci = Components.interfaces; const G_GDEBUG = false; @@ -11,8 +51,9 @@ const LIB_FILES = [ "chrome://global/content/url-classifier/moz/preferences.js", "chrome://global/content/url-classifier/moz/filesystem.js", "chrome://global/content/url-classifier/moz/debug.js", // req js/lang.js moz/prefs.js moz/filesystem.js + "chrome://global/content/url-classifier/moz/lang.js", - "chrome://global/content/url-classifier/map.js", + "chrome://global/content/url-classifier/multi-querier.js", ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { @@ -23,18 +64,25 @@ for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { } function UrlClassifierTableDomain() { - G_Map.call(this); this.debugZone = "trtable-domain"; + this.name = ''; + this.needsUpdate = false; } -UrlClassifierTableDomain.inherits(G_Map); - +UrlClassifierTableDomain.prototype.QueryInterface = function(iid) { + if (iid.equals(Components.interfaces.nsISupports) || + iid.equals(Components.interfaces.nsIUrlClassifierTable)) + return this; + Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; + return null; +} + /** * Look up a URL in a domain table * * @returns Boolean true if the url domain is in the table */ -UrlClassifierTableDomain.prototype.exists = function(url) { +UrlClassifierTableDomain.prototype.exists = function(url, callback) { var urlObj = Cc["@mozilla.org/network/standard-url;1"] .createInstance(Ci.nsIURL); urlObj.spec = url; @@ -43,13 +91,14 @@ UrlClassifierTableDomain.prototype.exists = function(url) { // We don't have a good way map from hosts to domains, so we instead try // each possibility. Could probably optimize to start at the second dot? + var possible = []; for (var i = 0; i < components.length - 1; i++) { host = components.slice(i).join("."); - var val = this.find_(host); - if (val) - return true; + possible.push(host); } - return false; + + // Run the possible domains against the db. + (new ExistsMultiQuerier(possible, this.name, callback)).run(); } diff --git a/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js b/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js index fd6492efa9b5..4988518f7b72 100644 --- a/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js +++ b/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js @@ -1,3 +1,43 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Tony Chang + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// TODO: Combine this file with other urlClassifierTable files and rename to +// nsUrlClassifierTable.js + const Cc = Components.classes; const Ci = Components.interfaces; const G_GDEBUG = false; @@ -12,11 +52,12 @@ const LIB_FILES = [ "chrome://global/content/url-classifier/moz/preferences.js", "chrome://global/content/url-classifier/moz/filesystem.js", "chrome://global/content/url-classifier/moz/debug.js", // req js/lang.js moz/prefs.js moz/filesystem.js + "chrome://global/content/url-classifier/moz/lang.js", - "chrome://global/content/url-classifier/map.js", "chrome://global/content/url-classifier/moz/base64.js", "chrome://global/content/url-classifier/moz/cryptohasher.js", "chrome://global/content/url-classifier/enchash-decrypter.js", + "chrome://global/content/url-classifier/multi-querier.js", ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { @@ -27,45 +68,39 @@ for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { } function UrlClassifierTableEnchash() { - G_Map.call(this); this.debugZone = "trtable-enchash"; + this.dbservice = Cc["@mozilla.org/url-classifier/dbservice;1"] + .getService(Ci.nsIUrlClassifierDBService); + this.name = ''; + this.needsUpdate = false; this.enchashDecrypter_ = new PROT_EnchashDecrypter(); } -UrlClassifierTableEnchash.inherits(G_Map); +UrlClassifierTableEnchash.prototype.QueryInterface = function(iid) { + if (iid.equals(Components.interfaces.nsISupports) || + iid.equals(Components.interfaces.nsIUrlClassifierTable)) + return this; + Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; + return null; +} /** * Look up a URL in an enchashDB - * - * @returns Boolean indicating whether the URL matches the regular - * expression contained in the table value */ -UrlClassifierTableEnchash.prototype.exists = function(url) { +UrlClassifierTableEnchash.prototype.exists = function(url, callback) { var host = this.enchashDecrypter_.getCanonicalHost(url); + var possible = []; for (var i = 0; i < PROT_EnchashDecrypter.MAX_DOTS + 1; i++) { - var key = this.enchashDecrypter_.getLookupKey(host); - - var encrypted = this.find_(key); - if (encrypted) { - G_Debug(this, "Enchash DB has host " + host); - - // We have encrypted regular expressions for this host. Let's - // decrypt them and see if we have a match. - var decrypted = this.enchashDecrypter_.decryptData(encrypted, host); - var res = this.enchashDecrypter_.parseRegExps(decrypted); - for (var j = 0; j < res.length; j++) { - if (res[j].test(url)) - return true; - } - } + possible.push(host); var index = host.indexOf("."); if (index == -1) break; host = host.substring(index + 1); } - return false; + // Run the possible domains against the db. + (new EnchashMultiQuerier(possible, this.name, callback, url)).run(); } diff --git a/toolkit/components/url-classifier/src/urlClassifierTableSite.js b/toolkit/components/url-classifier/src/urlClassifierTableSite.js deleted file mode 100644 index 4a950bc88593..000000000000 --- a/toolkit/components/url-classifier/src/urlClassifierTableSite.js +++ /dev/null @@ -1,118 +0,0 @@ -const Cc = Components.classes; -const Ci = Components.interfaces; -const G_GDEBUG = false; - -// Use subscript loader to load files. The files in ../content get mapped -// to chrome://global/content/url-classifier/. Order matters if one file depends -// on another file during initialization. -const LIB_FILES = [ - "chrome://global/content/url-classifier/js/lang.js", - - "chrome://global/content/url-classifier/moz/preferences.js", - "chrome://global/content/url-classifier/moz/filesystem.js", - "chrome://global/content/url-classifier/moz/debug.js", // req js/lang.js moz/prefs.js moz/filesystem.js - - "chrome://global/content/url-classifier/map.js", -]; - -for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { - //dump('*** loading subscript ' + libFile + '\n'); - Cc["@mozilla.org/moz/jssubscript-loader;1"] - .getService(Ci.mozIJSSubScriptLoader) - .loadSubScript(libFile); -} - -function UrlClassifierTableSite() { - G_Map.call(this); - this.debugZone = "trtable-site"; - this.ioService_ = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); -} - -UrlClassifierTableSite.inherits(G_Map); - -/** - * Look up a URL in a site DB - * - * @returns Boolean true if URL matches in table, we normalize based on - * part of the path - */ -UrlClassifierTableSite.prototype.exists = function(url) { - var nsIURI = this.ioService_.newURI(url, null, null); - var host = nsIURI.asciiHost; - var hostComponents = host.split("."); - - var path = nsIURI.path; - var pathComponents = path.split("/"); - - // We don't have a good way to convert a fully specified URL into a - // site. We try host name components with or without the first - // path component. - for (var i = 0; i < hostComponents.length - 1; i++) { - host = hostComponents.slice(i).join(".") + "/"; - var val = this.find_(host); - G_Debug(this, "Checking: " + host + " : " + val); - if (val) - return true; - - // The path starts with a "/", so we are interested in the second path - // component if it is available - if (pathComponents.length >= 2) { - host = host + pathComponents[1] + "/"; - var val = this.find_(host); - G_Debug(this, "Checking: " + host + " : " + val); - if (val) - return true; - } - } - - return false; -} - -// Module object -function UrlClassifierTableSiteMod() { - this.firstTime = true; - this.cid = Components.ID("{1e48f217-34e4-44a3-9b4a-9b66ed0a1201}"); - this.progid = "@mozilla.org/url-classifier/table;1?type=site"; -} - -UrlClassifierTableSiteMod.prototype.registerSelf = function(compMgr, fileSpec, loc, type) { - if (this.firstTime) { - this.firstTime = false; - throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; - } - compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar); - compMgr.registerFactoryLocation(this.cid, - "UrlClassifier Table Site Module", - this.progid, - fileSpec, - loc, - type); -}; - -UrlClassifierTableSiteMod.prototype.getClassObject = function(compMgr, cid, iid) { - if (!cid.equals(this.cid)) - throw Components.results.NS_ERROR_NO_INTERFACE; - if (!iid.equals(Ci.nsIFactory)) - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - - return this.factory; -} - -UrlClassifierTableSiteMod.prototype.canUnload = function(compMgr) { - return true; -} - -UrlClassifierTableSiteMod.prototype.factory = { - createInstance: function(outer, iid) { - if (outer != null) - throw Components.results.NS_ERROR_NO_AGGREGATION; - return (new UrlClassifierTableSite()).QueryInterface(iid); - } -}; - -var SiteModInst = new UrlClassifierTableSiteMod(); - -function NSGetModule(compMgr, fileSpec) { - return SiteModInst; -} diff --git a/toolkit/components/url-classifier/src/urlClassifierTableUrl.js b/toolkit/components/url-classifier/src/urlClassifierTableUrl.js index a79684920a94..21d389aa6a21 100644 --- a/toolkit/components/url-classifier/src/urlClassifierTableUrl.js +++ b/toolkit/components/url-classifier/src/urlClassifierTableUrl.js @@ -1,3 +1,43 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Tony Chang + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// TODO: Combine this file with other urlClassifierTable files and rename to +// nsUrlClassifierTable.js + const Cc = Components.classes; const Ci = Components.interfaces; const G_GDEBUG = false; @@ -12,7 +52,6 @@ const LIB_FILES = [ "chrome://global/content/url-classifier/moz/filesystem.js", "chrome://global/content/url-classifier/moz/debug.js", // req js/lang.js moz/prefs.js moz/filesystem.js - "chrome://global/content/url-classifier/map.js", "chrome://global/content/url-classifier/url-canonicalizer.js" ]; @@ -24,22 +63,33 @@ for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { } function UrlClassifierTableUrl() { - G_Map.call(this); this.debugZone = "trtable-url"; + this.dbservice_ = Cc["@mozilla.org/url-classifier/dbservice;1"] + .getService(Ci.nsIUrlClassifierDBService); + this.name = ''; + this.needsUpdate = false; } -UrlClassifierTableUrl.inherits(G_Map); +UrlClassifierTableUrl.prototype.QueryInterface = function(iid) { + if (iid.equals(Components.interfaces.nsISupports) || + iid.equals(Components.interfaces.nsIUrlClassifierTable)) + return this; + Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; + return null; +} /** * Look up a URL in a URL table - * - * @returns Boolean true if the canonicalized url is in the table */ -UrlClassifierTableUrl.prototype.exists = function(url) { +UrlClassifierTableUrl.prototype.exists = function(url, callback) { var canonicalized = PROT_URLCanonicalizer.canonicalizeURL_(url); - // Uncomment for debugging G_Debug(this, "Looking up: " + url + " (" + canonicalized + ")"); - return this.find_(canonicalized); + + function dbCallback(v) { + G_Debug("dbCallback", "Looked up " + url + ": " + v + "|"); + callback.handleEvent(v.length > 0); + } + this.dbservice_.exists(this.name, url, dbCallback); } diff --git a/toolkit/components/url-classifier/src/urlListManager.js b/toolkit/components/url-classifier/src/urlListManager.js index cd3ab530e39c..633311f62e66 100644 --- a/toolkit/components/url-classifier/src/urlListManager.js +++ b/toolkit/components/url-classifier/src/urlListManager.js @@ -1,6 +1,45 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Url Classifier code + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Tony Chang + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// TODO: Rename this file to nsUrlClassifierListManager.js + const Cc = Components.classes; const Ci = Components.interfaces; -const G_GDEBUG = true; +const G_GDEBUG = false; // Use subscript loader to load files. The files in ../content get mapped // to chrome://global/content/url-classifier/. Order matters if one file depends