зеркало из https://github.com/mozilla/pjs.git
Bug 346184: If urlclassifier.sqlite is removed, db is not repopulated
patch: check db tables before sending an update request r=darin
This commit is contained in:
Родитель
da606dc502
Коммит
2b2df42abb
|
@ -439,6 +439,35 @@ PROT_ListManager.prototype.checkForUpdates = function() {
|
|||
G_Debug(this, 'checkForUpdates: no update server url');
|
||||
return false;
|
||||
}
|
||||
// Check to make sure our tables still exist (maybe the db got corrupted or
|
||||
// the user deleted the file). If not, we need to reset the table version
|
||||
// before sending the update check.
|
||||
var tableNames = [];
|
||||
for (var tableName in this.tablesKnown_) {
|
||||
tableNames.push(tableName);
|
||||
}
|
||||
var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
|
||||
.getService(Ci.nsIUrlClassifierDBService);
|
||||
dbService.checkTables(tableNames.join(","),
|
||||
BindToObject(this.makeUpdateRequest_, this));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that fires the actual HTTP update request.
|
||||
* First we reset any tables that have disappeared.
|
||||
* @param tableNames String comma separated list of tables that
|
||||
* don't exist
|
||||
*/
|
||||
PROT_ListManager.prototype.makeUpdateRequest_ = function(tableNames) {
|
||||
// Clear prefs that track table version if they no longer exist in the db.
|
||||
var tables = tableNames.split(",");
|
||||
for (var i = 0; i < tables.length; ++i) {
|
||||
G_Debug(this, "Table |" + tables[i] + "| no longer exists, clearing pref.");
|
||||
this.prefs_.clearPref(kTableVersionPrefPrefix + tables[i]);
|
||||
}
|
||||
|
||||
// Ok, now reload the table version.
|
||||
this.loadTableVersions_();
|
||||
|
||||
G_Debug(this, 'checkForUpdates: scheduling request..');
|
||||
|
@ -449,69 +478,12 @@ PROT_ListManager.prototype.checkForUpdates = function() {
|
|||
streamer.updateUrl = url;
|
||||
} catch (e) {
|
||||
G_Debug(this, 'invalid url');
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
return streamer.downloadUpdates(BindToObject(this.setTableVersion_, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the server response, extract out the new table lines and table
|
||||
* version numbers. If the table has a mac, also check to see if it matches
|
||||
* the data.
|
||||
*
|
||||
* @param data String update string from the server
|
||||
* @return String The same update string sans tables with invalid macs.
|
||||
*/
|
||||
PROT_ListManager.prototype.checkMac_ = function(data) {
|
||||
var dataTables = data.split('\n\n');
|
||||
var returnString = "";
|
||||
|
||||
for (var table = null, t = 0; table = dataTables[t]; ++t) {
|
||||
var firstLineEnd = table.indexOf("\n");
|
||||
while (firstLineEnd == 0) {
|
||||
// Skip leading blank lines
|
||||
table = table.substring(1);
|
||||
firstLineEnd = table.indexOf("\n");
|
||||
}
|
||||
if (firstLineEnd == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var versionLine = table.substring(0, firstLineEnd);
|
||||
var versionParser = new PROT_VersionParser("dummy");
|
||||
if (!versionParser.fromString(versionLine)) {
|
||||
// Failed to parse the version string, skip this table.
|
||||
G_Debug(this, "Failed to parse version string");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (versionParser.mac && versionParser.macval.length > 0) {
|
||||
// Includes a mac, so we check it.
|
||||
var updateData = table.substring(firstLineEnd + 1) + '\n';
|
||||
if (!this.urlCrypto_)
|
||||
this.urlCrypto_ = new PROT_UrlCrypto();
|
||||
|
||||
var computedMac = this.urlCrypto_.computeMac(updateData);
|
||||
if (computedMac != versionParser.macval) {
|
||||
G_Debug(this, "mac doesn't match: " + computedMac + " != " +
|
||||
versionParser.macval)
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// No mac in the return. Check to see if it's required. If it is
|
||||
// required, skip this data.
|
||||
if (this.tablesKnown_[versionParser.type] &&
|
||||
this.tablesKnown_[versionParser.type].requireMac) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything looks ok, add it to the return string.
|
||||
returnString += table + "\n\n";
|
||||
if (!streamer.downloadUpdates(BindToObject(this.setTableVersion_, this))) {
|
||||
G_Debug(this, "pending update, wait until later");
|
||||
}
|
||||
|
||||
return returnString;
|
||||
}
|
||||
|
||||
PROT_ListManager.prototype.QueryInterface = function(iid) {
|
||||
|
|
|
@ -49,7 +49,7 @@ interface nsIUrlClassifierCallback : nsISupports {
|
|||
* It provides async methods for querying and updating the database. As the
|
||||
* methods complete, they call the callback function.
|
||||
*/
|
||||
[scriptable, uuid(61759a52-fbbb-4c5e-b1df-fce67b6d10c8)]
|
||||
[scriptable, uuid(211d5360-4af6-4a1d-99c1-926d35861eaf)]
|
||||
interface nsIUrlClassifierDBService : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -61,6 +61,14 @@ interface nsIUrlClassifierDBService : nsISupports
|
|||
void exists(in ACString tableName, in ACString key,
|
||||
in nsIUrlClassifierCallback c);
|
||||
|
||||
/**
|
||||
* Checks to see if the tables exist. tableNames is a comma separated list
|
||||
* of table names to check. The callback is called with a comma separated
|
||||
* list of tables that no longer exist (either the db is corrupted or the
|
||||
* user deleted the file).
|
||||
*/
|
||||
void checkTables(in ACString tableNames, in nsIUrlClassifierCallback c);
|
||||
|
||||
/**
|
||||
* Updates the table in the background. Calls callback after each table
|
||||
* completes processing with the new table line as the parameter. This
|
||||
|
|
|
@ -72,37 +72,6 @@ static nsUrlClassifierDBService* sUrlClassifierDBService;
|
|||
// Thread that we do the updates on.
|
||||
static nsIThread* gDbBackgroundThread = nsnull;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Wrapper for JS-implemented nsIUrlClassifierCallback that protects against
|
||||
// bug 337492. We should be able to remove this code once that bug is fixed.
|
||||
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
class nsUrlClassifierCallbackWrapper : public nsIUrlClassifierCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_FORWARD_NSIURLCLASSIFIERCALLBACK(mInner->)
|
||||
|
||||
nsUrlClassifierCallbackWrapper(nsIUrlClassifierCallback *inner)
|
||||
: mInner(inner)
|
||||
{
|
||||
NS_ADDREF(mInner);
|
||||
}
|
||||
|
||||
~nsUrlClassifierCallbackWrapper()
|
||||
{
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
NS_ProxyRelease(mainThread, mInner);
|
||||
}
|
||||
|
||||
private:
|
||||
nsIUrlClassifierCallback *mInner;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierCallbackWrapper,
|
||||
nsIUrlClassifierCallback)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Actual worker implemenatation
|
||||
class nsUrlClassifierDBServiceWorker : public nsIUrlClassifierDBServiceWorker
|
||||
|
@ -134,14 +103,14 @@ private:
|
|||
// Handle a new table line of the form [table-name #.####]. We create the
|
||||
// table if it doesn't exist and set the aTableName, aUpdateStatement,
|
||||
// and aDeleteStatement.
|
||||
nsresult ProcessNewTable(const nsDependentCSubstring& aLine,
|
||||
nsresult ProcessNewTable(const nsCSubstring& aLine,
|
||||
nsCString* aTableName,
|
||||
mozIStorageStatement** aUpdateStatement,
|
||||
mozIStorageStatement** aDeleteStatement);
|
||||
|
||||
// Handle an add or remove line. We execute additional update or delete
|
||||
// statements.
|
||||
nsresult ProcessUpdateTable(const nsDependentCSubstring& aLine,
|
||||
nsresult ProcessUpdateTable(const nsCSubstring& aLine,
|
||||
const nsCString& aTableName,
|
||||
mozIStorageStatement* aUpdateStatement,
|
||||
mozIStorageStatement* aDeleteStatement);
|
||||
|
@ -224,6 +193,48 @@ nsUrlClassifierDBServiceWorker::Exists(const nsACString& tableName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// We get a comma separated list of table names. For each table that doesn't
|
||||
// exist, we return it in a comma separated list via the callback.
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBServiceWorker::CheckTables(const nsACString & tableNames,
|
||||
nsIUrlClassifierCallback *c)
|
||||
{
|
||||
nsresult rv = OpenDb();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Unable to open database");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCAutoString changedTables;
|
||||
|
||||
// tablesNames is a comma separated list, so get each table name out for
|
||||
// checking.
|
||||
PRUint32 cur = 0;
|
||||
PRInt32 next;
|
||||
while (cur < tableNames.Length()) {
|
||||
next = tableNames.FindChar(',', cur);
|
||||
if (kNotFound == next) {
|
||||
next = tableNames.Length();
|
||||
}
|
||||
const nsCSubstring &tableName = Substring(tableNames, cur, next - cur);
|
||||
cur = next + 1;
|
||||
|
||||
nsCString dbTableName;
|
||||
GetDbTableName(tableName, &dbTableName);
|
||||
PRBool exists;
|
||||
nsresult rv = mConnection->TableExists(dbTableName, &exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!exists) {
|
||||
if (changedTables.Length() > 0)
|
||||
changedTables.Append(",");
|
||||
changedTables.Append(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
c->HandleEvent(changedTables);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Do a batch update of the database. After we complete processing a table,
|
||||
// we call the callback with the table line.
|
||||
NS_IMETHODIMP
|
||||
|
@ -252,8 +263,7 @@ nsUrlClassifierDBServiceWorker::UpdateTables(const nsACString& updateString,
|
|||
while(cur < updateString.Length() &&
|
||||
(next = updateString.FindChar('\n', cur)) != kNotFound) {
|
||||
count ++;
|
||||
const nsDependentCSubstring &line = Substring(updateString,
|
||||
cur, next - cur);
|
||||
const nsCSubstring &line = Substring(updateString, cur, next - cur);
|
||||
cur = next + 1; // prepare for next run
|
||||
|
||||
// Skip blank lines
|
||||
|
@ -319,7 +329,7 @@ nsUrlClassifierDBServiceWorker::Update(const nsACString& chunk)
|
|||
} else {
|
||||
PRUint32 numTables = mTableUpdateLines.Length();
|
||||
if (numTables > 0) {
|
||||
const nsDependentCSubstring &line = Substring(
|
||||
const nsCSubstring &line = Substring(
|
||||
mTableUpdateLines[numTables - 1], 0);
|
||||
|
||||
rv = ProcessNewTable(line, &dbTableName,
|
||||
|
@ -333,8 +343,7 @@ nsUrlClassifierDBServiceWorker::Update(const nsACString& chunk)
|
|||
PRInt32 next;
|
||||
while(cur < updateString.Length() &&
|
||||
(next = updateString.FindChar('\n', cur)) != kNotFound) {
|
||||
const nsDependentCSubstring &line = Substring(updateString,
|
||||
cur, next - cur);
|
||||
const nsCSubstring &line = Substring(updateString, cur, next - cur);
|
||||
cur = next + 1; // prepare for next run
|
||||
|
||||
// Skip blank lines
|
||||
|
@ -415,7 +424,7 @@ nsUrlClassifierDBServiceWorker::CloseDb()
|
|||
|
||||
nsresult
|
||||
nsUrlClassifierDBServiceWorker::ProcessNewTable(
|
||||
const nsDependentCSubstring& aLine,
|
||||
const nsCSubstring& aLine,
|
||||
nsCString* aDbTableName,
|
||||
mozIStorageStatement** aUpdateStatement,
|
||||
mozIStorageStatement** aDeleteStatement)
|
||||
|
@ -427,7 +436,7 @@ nsUrlClassifierDBServiceWorker::ProcessNewTable(
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const nsDependentCSubstring &tableName = Substring(aLine, 1, spacePos - 1);
|
||||
const nsCSubstring &tableName = Substring(aLine, 1, spacePos - 1);
|
||||
GetDbTableName(tableName, aDbTableName);
|
||||
|
||||
// Create the table
|
||||
|
@ -456,7 +465,7 @@ nsUrlClassifierDBServiceWorker::ProcessNewTable(
|
|||
|
||||
nsresult
|
||||
nsUrlClassifierDBServiceWorker::ProcessUpdateTable(
|
||||
const nsDependentCSubstring& aLine,
|
||||
const nsCSubstring& aLine,
|
||||
const nsCString& aTableName,
|
||||
mozIStorageStatement* aUpdateStatement,
|
||||
mozIStorageStatement* aDeleteStatement)
|
||||
|
@ -479,8 +488,8 @@ nsUrlClassifierDBServiceWorker::ProcessUpdateTable(
|
|||
|
||||
if ('+' == op && spacePos != kNotFound) {
|
||||
// Insert operation of the form "+KEY\tVALUE"
|
||||
const nsDependentCSubstring &key = Substring(aLine, 1, spacePos - 1);
|
||||
const nsDependentCSubstring &value = Substring(aLine, spacePos + 1);
|
||||
const nsCSubstring &key = Substring(aLine, 1, spacePos - 1);
|
||||
const nsCSubstring &value = Substring(aLine, spacePos + 1);
|
||||
aUpdateStatement->BindUTF8StringParameter(0, key);
|
||||
aUpdateStatement->BindUTF8StringParameter(1, value);
|
||||
|
||||
|
@ -490,11 +499,11 @@ nsUrlClassifierDBServiceWorker::ProcessUpdateTable(
|
|||
// Remove operation of the form "-KEY"
|
||||
if (spacePos == kNotFound) {
|
||||
// No trailing tab
|
||||
const nsDependentCSubstring &key = Substring(aLine, 1);
|
||||
const nsCSubstring &key = Substring(aLine, 1);
|
||||
aDeleteStatement->BindUTF8StringParameter(0, key);
|
||||
} else {
|
||||
// With trailing tab
|
||||
const nsDependentCSubstring &key = Substring(aLine, 1, spacePos - 1);
|
||||
const nsCSubstring &key = Substring(aLine, 1, spacePos - 1);
|
||||
aDeleteStatement->BindUTF8StringParameter(0, key);
|
||||
}
|
||||
|
||||
|
@ -640,16 +649,12 @@ nsUrlClassifierDBService::Exists(const nsACString& tableName,
|
|||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIUrlClassifierCallback> wrapper =
|
||||
new nsUrlClassifierCallbackWrapper(c);
|
||||
NS_ENSURE_TRUE(wrapper, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv;
|
||||
// The proxy callback uses the current thread.
|
||||
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
||||
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
||||
NS_GET_IID(nsIUrlClassifierCallback),
|
||||
wrapper,
|
||||
c,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxyCallback));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -667,21 +672,45 @@ nsUrlClassifierDBService::Exists(const nsACString& tableName,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::UpdateTables(const nsACString& updateString,
|
||||
nsIUrlClassifierCallback *c)
|
||||
nsUrlClassifierDBService::CheckTables(const nsACString & tableNames,
|
||||
nsIUrlClassifierCallback *c)
|
||||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIUrlClassifierCallback> wrapper =
|
||||
new nsUrlClassifierCallbackWrapper(c);
|
||||
NS_ENSURE_TRUE(wrapper, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv;
|
||||
// The proxy callback uses the current thread.
|
||||
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
||||
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
||||
NS_GET_IID(nsIUrlClassifierCallback),
|
||||
wrapper,
|
||||
c,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxyCallback));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The actual worker uses the background thread.
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> proxy;
|
||||
rv = NS_GetProxyForObject(gDbBackgroundThread,
|
||||
NS_GET_IID(nsIUrlClassifierDBServiceWorker),
|
||||
mWorker,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return proxy->CheckTables(tableNames, proxyCallback);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::UpdateTables(const nsACString& updateString,
|
||||
nsIUrlClassifierCallback *c)
|
||||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult rv;
|
||||
// The proxy callback uses the current thread.
|
||||
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
||||
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
||||
NS_GET_IID(nsIUrlClassifierCallback),
|
||||
c,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxyCallback));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -722,16 +751,12 @@ nsUrlClassifierDBService::Finish(nsIUrlClassifierCallback *c)
|
|||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIUrlClassifierCallback> wrapper =
|
||||
new nsUrlClassifierCallbackWrapper(c);
|
||||
NS_ENSURE_TRUE(wrapper, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv;
|
||||
// The proxy callback uses the current thread.
|
||||
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
||||
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
||||
NS_GET_IID(nsIUrlClassifierCallback),
|
||||
wrapper,
|
||||
c,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxyCallback));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
Загрузка…
Ссылка в новой задаче