mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 336203 (for tony@ponderer.org) r=darin Add new safe browsing C++ service
This commit is contained in:
parent
9b87de92dc
commit
4db436d5f2
@ -85,6 +85,7 @@ REQUIRES = \
|
||||
unicharutil \
|
||||
xuldoc \
|
||||
alerts \
|
||||
url-classifier \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = nsToolkitCompsCID.h
|
||||
@ -96,6 +97,7 @@ LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../startup/src \
|
||||
-I$(srcdir)/../typeaheadfind/src \
|
||||
-I$(srcdir)/../alerts/src \
|
||||
-I$(srcdir)/../url-classifier/src \
|
||||
$(NULL)
|
||||
|
||||
SHARED_LIBRARY_LIBS = \
|
||||
@ -113,6 +115,10 @@ ifdef ALERTS_SERVICE
|
||||
SHARED_LIBRARY_LIBS += ../alerts/src/$(LIB_PREFIX)alerts_s.$(LIB_SUFFIX)
|
||||
endif
|
||||
|
||||
ifdef MOZ_URL_CLASSIFIER
|
||||
SHARED_LIBRARY_LIBS += $(DIST)/lib/$(LIB_PREFIX)urlclassifier_s.$(LIB_SUFFIX)
|
||||
endif
|
||||
|
||||
ifndef MOZ_SUITE
|
||||
# XXX Suite isn't ready to build this just yet
|
||||
SHARED_LIBRARY_LIBS += ../typeaheadfind/src/$(LIB_PREFIX)fastfind_s.$(LIB_SUFFIX)
|
||||
|
@ -74,6 +74,9 @@
|
||||
#define NS_TYPEAHEADFIND_CONTRACTID \
|
||||
"@mozilla.org/typeaheadfind;1"
|
||||
|
||||
#define NS_URLCLASSIFIERDBSERVICE_CONTRACTID \
|
||||
"@mozilla.org/url-classifier/dbservice;1"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// {A0CCAAF8-09DA-44D8-B250-9AC3E93C8117}
|
||||
@ -115,3 +118,5 @@
|
||||
#define NS_TYPEAHEADFIND_CID \
|
||||
{ 0xe7f70966, 0x9a37, 0x48d7, { 0x8a, 0xeb, 0x35, 0x99, 0x8f, 0x31, 0x09, 0x0e} }
|
||||
|
||||
#define NS_URLCLASSIFIERDBSERVICE_CID \
|
||||
{ 0x5eb7c3c1, 0xec1f, 0x4007, { 0x87, 0xcc, 0xee, 0xfb, 0x37, 0xd6, 0x8c, 0xe6} }
|
||||
|
@ -54,6 +54,10 @@
|
||||
#include "nsTypeAheadFind.h"
|
||||
#endif // MOZ_SUITE
|
||||
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
#include "nsUrlClassifierDBService.h"
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppStartup, Init)
|
||||
@ -73,6 +77,11 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadProxy)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTypeAheadFind)
|
||||
#endif // MOZ_SUITE
|
||||
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsUrlClassifierDBService,
|
||||
nsUrlClassifierDBService::GetInstance)
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const nsModuleComponentInfo components[] =
|
||||
@ -110,6 +119,12 @@ static const nsModuleComponentInfo components[] =
|
||||
nsTypeAheadFindConstructor
|
||||
},
|
||||
#endif // MOZ_SUITE
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
{ "Url Classifier DB Service",
|
||||
NS_URLCLASSIFIERDBSERVICE_CID,
|
||||
NS_URLCLASSIFIERDBSERVICE_CONTRACTID,
|
||||
nsUrlClassifierDBServiceConstructor },
|
||||
#endif
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE(nsToolkitCompsModule, components)
|
||||
|
@ -8,7 +8,8 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MODULE = url-classifier
|
||||
XPIDL_MODULE = url-classifier
|
||||
|
||||
XPIDLSRCS = nsIUrlClassifierTable.idl \
|
||||
XPIDLSRCS = nsIUrlClassifierDBService.idl \
|
||||
nsIUrlClassifierTable.idl \
|
||||
nsIUrlListManager.idl \
|
||||
$(NULL)
|
||||
|
||||
|
@ -0,0 +1,81 @@
|
||||
/* ***** 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 <tony@ponderer.org> (original author)
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
// Interface for JS function callbacks
|
||||
[scriptable, function, uuid(4ca27b6b-a674-4b3d-ab30-d21e2da2dffb)]
|
||||
interface nsIUrlClassifierCallback : nsISupports {
|
||||
void handleEvent(in ACString value);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a proxy class that is instantiated and called from the JS thread.
|
||||
* It provides async methods for querying and updating the database. As the
|
||||
* methods complete, they call the callback function.
|
||||
*/
|
||||
[scriptable, uuid(88519724-2225-4b4f-8ba7-365b4d138c3a)]
|
||||
interface nsIUrlClassifierDBService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Looks up a key in the database. After it finds a value, it calls
|
||||
* callback with the value as the first param. If the key is not in
|
||||
* the db or the table does not exist, the callback is called with
|
||||
* an empty string parameter.
|
||||
*/
|
||||
void exists(in ACString tableName, in ACString key,
|
||||
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
|
||||
* allows us to keep track of the table version in our main thread.
|
||||
*/
|
||||
void updateTables(in ACString updateString, in nsIUrlClassifierCallback c);
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for the actual worker thread. Implementations of this need not
|
||||
* be thread aware and just work on the database.
|
||||
*/
|
||||
[scriptable, uuid(5d405325-2ba1-4040-b69b-8bda8353d3d3)]
|
||||
interface nsIUrlClassifierDBServiceWorker : nsIUrlClassifierDBService
|
||||
{
|
||||
// Provide a way to forcibly close the db connection.
|
||||
void closeDb();
|
||||
};
|
@ -5,6 +5,27 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = url-classifier
|
||||
LIBRARY_NAME = urlclassifier_s
|
||||
XPIDL_MODULE = url-classifier
|
||||
MOZILLA_INTERNAL_API = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
|
||||
REQUIRES = storage \
|
||||
string \
|
||||
xpcom \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsUrlClassifierDBService.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../../build
|
||||
$(NULL)
|
||||
|
||||
|
||||
# EXTRA_COMPONENTS installs components written in JS to dist/bin/components
|
||||
EXTRA_COMPONENTS = urlClassifierTableUrl.js \
|
||||
urlClassifierTableDomain.js \
|
||||
|
@ -0,0 +1,634 @@
|
||||
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 <tony@ponderer.org> (original author)
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "mozIStorageService.h"
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
#include "mozStorageCID.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIDirectoryService.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIProperties.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsUrlClassifierDBService.h"
|
||||
#include "nsString.h"
|
||||
#include "plevent.h"
|
||||
#include "prlog.h"
|
||||
#include "prmon.h"
|
||||
#include "prthread.h"
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
static const PRLogModuleInfo *gUrlClassifierDbServiceLog = nsnull;
|
||||
#define LOG(args) PR_LOG(gUrlClassifierDbServiceLog, PR_LOG_DEBUG, args)
|
||||
#else
|
||||
#define LOG(args)
|
||||
#endif
|
||||
|
||||
#define DATABASE_FILENAME "urlclassifier.sqlite"
|
||||
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
|
||||
|
||||
// Singleton instance.
|
||||
static nsUrlClassifierDBService* sUrlClassifierDBService;
|
||||
|
||||
// The event queue used to pass around messages between threads.
|
||||
static nsIEventQueue* gEventQ = nsnull;
|
||||
|
||||
// Used to ensure that the event queue is initialized before
|
||||
static PRMonitor *gMonitor = nsnull;
|
||||
|
||||
// Thread that we do the updates on.
|
||||
static PRThread* gDbBackgroundThread = nsnull;
|
||||
|
||||
// The flag that tells us it's time to stop the background thread.
|
||||
static PRBool gKeepRunning = PR_TRUE;
|
||||
|
||||
// The background thread event loop. Creates an nsIEventQueue and processes
|
||||
// jobs as they come in.
|
||||
PR_STATIC_CALLBACK(void) EventLoop(void *arg);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Actual worker implemenatation
|
||||
class nsUrlClassifierDBServiceWorker : public nsIUrlClassifierDBServiceWorker
|
||||
{
|
||||
public:
|
||||
nsUrlClassifierDBServiceWorker();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIURLCLASSIFIERDBSERVICE
|
||||
NS_DECL_NSIURLCLASSIFIERDBSERVICEWORKER
|
||||
|
||||
private:
|
||||
// No subclassing
|
||||
~nsUrlClassifierDBServiceWorker();
|
||||
|
||||
// Disallow copy constructor
|
||||
nsUrlClassifierDBServiceWorker(nsUrlClassifierDBServiceWorker&);
|
||||
|
||||
// Table names have hyphens in them, which SQL doesn't allow,
|
||||
// so we convert them to underscores.
|
||||
void GetDbTableName(const nsACString& aTableName, nsCString* aDbTableName);
|
||||
|
||||
// Try to open the db, DATABASE_FILENAME.
|
||||
nsresult OpenDb();
|
||||
|
||||
// Create a table in the db if it doesn't exist.
|
||||
nsresult MaybeCreateTable(const nsCString& aTableName);
|
||||
|
||||
// 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,
|
||||
nsCString* aTableName,
|
||||
mozIStorageStatement** aUpdateStatement,
|
||||
mozIStorageStatement** aDeleteStatement);
|
||||
|
||||
// Handle an add or remove line. We execute additional update or delete
|
||||
// statements.
|
||||
nsresult ProcessUpdateTable(const nsDependentCSubstring& aLine,
|
||||
const nsCString& aTableName,
|
||||
mozIStorageStatement* aUpdateStatement,
|
||||
mozIStorageStatement* aDeleteStatement);
|
||||
|
||||
// Holds a connection to the Db. We lazily initialize this because it has
|
||||
// to be created in the background thread (currently mozStorageConnection
|
||||
// isn't thread safe).
|
||||
mozIStorageConnection* mConnection;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierDBServiceWorker,
|
||||
nsIUrlClassifierDBServiceWorker)
|
||||
|
||||
nsUrlClassifierDBServiceWorker::nsUrlClassifierDBServiceWorker()
|
||||
: mConnection(nsnull)
|
||||
{
|
||||
}
|
||||
nsUrlClassifierDBServiceWorker::~nsUrlClassifierDBServiceWorker()
|
||||
{
|
||||
NS_ASSERTION(mConnection != nsnull,
|
||||
"Db connection not closed, leaking memory! Call CloseDb "
|
||||
"to close the connection.");
|
||||
}
|
||||
|
||||
|
||||
// Lookup a key in the db.
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBServiceWorker::Exists(const nsACString& tableName,
|
||||
const nsACString& key,
|
||||
nsIUrlClassifierCallback *c) {
|
||||
nsresult rv = OpenDb();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Unable to open database");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCAutoString dbTableName;
|
||||
GetDbTableName(tableName, &dbTableName);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> selectStatement;
|
||||
nsCAutoString statement;
|
||||
statement.AssignLiteral("SELECT value FROM ");
|
||||
statement.Append(dbTableName);
|
||||
statement.AppendLiteral(" WHERE key = ?1");
|
||||
nsCOMPtr<mozIStorageStatement> foostatement;
|
||||
|
||||
nsString value;
|
||||
rv = mConnection->CreateStatement(statement,
|
||||
getter_AddRefs(selectStatement));
|
||||
|
||||
// If CreateStatment failed, this probably means the table doesn't exist.
|
||||
// That's ok, we just return an emptry string.
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = selectStatement->BindUTF8StringParameter(0, key);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
rv = selectStatement->ExecuteStep(&hasMore);
|
||||
// If the table has any columns, take the first value.
|
||||
if (NS_SUCCEEDED(rv) && hasMore) {
|
||||
selectStatement->GetString(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
c->HandleEvent(NS_ConvertUTF16toUTF8(value));
|
||||
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
|
||||
nsUrlClassifierDBServiceWorker::UpdateTables(const nsACString& updateString,
|
||||
nsIUrlClassifierCallback *c) {
|
||||
LOG(("Updating tables\n"));
|
||||
|
||||
nsresult rv = OpenDb();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Unable to open database");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = mConnection->BeginTransaction();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to begin transaction");
|
||||
|
||||
// Split the update string into lines
|
||||
PRUint32 cur = 0;
|
||||
PRInt32 next;
|
||||
PRInt32 count = 0;
|
||||
nsCAutoString dbTableName;
|
||||
nsCAutoString lastTableLine;
|
||||
nsCOMPtr<mozIStorageStatement> updateStatement;
|
||||
nsCOMPtr<mozIStorageStatement> deleteStatement;
|
||||
while(cur < updateString.Length() &&
|
||||
(next = updateString.FindChar('\n', cur)) != kNotFound) {
|
||||
count ++;
|
||||
const nsDependentCSubstring &line = Substring(updateString,
|
||||
cur, next - cur);
|
||||
cur = next + 1; // prepare for next run
|
||||
|
||||
// Skip blank lines
|
||||
if (line.Length() == 0)
|
||||
continue;
|
||||
|
||||
if ('[' == line[0]) {
|
||||
rv = ProcessNewTable(line, &dbTableName,
|
||||
getter_AddRefs(updateStatement),
|
||||
getter_AddRefs(deleteStatement));
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "malformed table line");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// If it's a new table, we must have completed the last table.
|
||||
// Go ahead and post the completion to the UI thread.
|
||||
if (lastTableLine.Length() > 0)
|
||||
c->HandleEvent(lastTableLine);
|
||||
lastTableLine.Assign(line);
|
||||
}
|
||||
} else {
|
||||
rv = ProcessUpdateTable(line, dbTableName, updateStatement,
|
||||
deleteStatement);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "malformed update line");
|
||||
}
|
||||
}
|
||||
LOG(("Num update lines: %d\n", count));
|
||||
|
||||
// Commit the transaction
|
||||
rv = mConnection->CommitTransaction();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to commit");
|
||||
|
||||
if (lastTableLine.Length() > 0)
|
||||
c->HandleEvent(lastTableLine);
|
||||
LOG(("Finishing table update\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Allows the main thread to delete the connection which may be in
|
||||
// a background thread.
|
||||
// XXX This could be turned into a single shutdown event so the logic
|
||||
// is simpler in nsUrlClassifierDBService::Shutdown.
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBServiceWorker::CloseDb()
|
||||
{
|
||||
if (mConnection != nsnull) {
|
||||
delete mConnection;
|
||||
mConnection = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierDBServiceWorker::ProcessNewTable(
|
||||
const nsDependentCSubstring& aLine,
|
||||
nsCString* aDbTableName,
|
||||
mozIStorageStatement** aUpdateStatement,
|
||||
mozIStorageStatement** aDeleteStatement)
|
||||
{
|
||||
// The line format is "[table-name #.####]" or "[table-name #.#### update]"
|
||||
PRInt32 spacePos = aLine.FindChar(' ');
|
||||
if (spacePos == kNotFound) {
|
||||
// bad table header
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const nsDependentCSubstring &tableName = Substring(aLine, 1, spacePos - 1);
|
||||
GetDbTableName(tableName, aDbTableName);
|
||||
|
||||
// Create the table
|
||||
nsresult rv = MaybeCreateTable(*aDbTableName);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
LOG(("Create table ok.\n"));
|
||||
|
||||
// insert statement
|
||||
nsCAutoString statement;
|
||||
statement.AssignLiteral("INSERT OR REPLACE INTO ");
|
||||
statement.Append(*aDbTableName);
|
||||
statement.AppendLiteral(" VALUES (?1, ?2)");
|
||||
rv = mConnection->CreateStatement(statement, aUpdateStatement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// delete statement
|
||||
statement.AssignLiteral("DELETE FROM ");
|
||||
statement.Append(*aDbTableName);
|
||||
statement.AppendLiteral(" WHERE key = ?1");
|
||||
rv = mConnection->CreateStatement(statement, aDeleteStatement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierDBServiceWorker::ProcessUpdateTable(
|
||||
const nsDependentCSubstring& aLine,
|
||||
const nsCString& aTableName,
|
||||
mozIStorageStatement* aUpdateStatement,
|
||||
mozIStorageStatement* aDeleteStatement)
|
||||
{
|
||||
// We should have seen a table name line by now.
|
||||
if (aTableName.Length() == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!aUpdateStatement || !aDeleteStatement) {
|
||||
NS_NOTREACHED("Statements NULL but table is not");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// There should at least be an op char and a key
|
||||
if (aLine.Length() < 2)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
char op = aLine[0];
|
||||
PRInt32 spacePos = aLine.FindChar('\t');
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if ('+' == op && spacePos != kNotFound) {
|
||||
// Insert operation of the form "+KEY VALUE"
|
||||
const nsDependentCSubstring &key = Substring(aLine, 1, spacePos - 1);
|
||||
const nsDependentCSubstring &value = Substring(aLine, spacePos + 1);
|
||||
aUpdateStatement->BindUTF8StringParameter(0, key);
|
||||
aUpdateStatement->BindUTF8StringParameter(1, value);
|
||||
|
||||
rv = aUpdateStatement->Execute();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to update");
|
||||
} else if ('-' == op && spacePos == kNotFound) {
|
||||
// Remove operation of the form "-KEY"
|
||||
const nsDependentCSubstring &key = Substring(aLine, 1);
|
||||
aDeleteStatement->BindUTF8StringParameter(0, key);
|
||||
|
||||
rv = aDeleteStatement->Execute();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to delete");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierDBServiceWorker::OpenDb()
|
||||
{
|
||||
// Connection already open, don't do anything.
|
||||
if (mConnection != nsnull)
|
||||
return NS_OK;
|
||||
|
||||
// Compute database filename
|
||||
nsCOMPtr<nsIFile> dbFile;
|
||||
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(dbFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = dbFile->Append(NS_LITERAL_STRING(DATABASE_FILENAME));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// open the connection
|
||||
nsCOMPtr<mozIStorageService> storageService =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return storageService->OpenDatabase(dbFile, &mConnection);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierDBServiceWorker::MaybeCreateTable(const nsCString& aTableName) {
|
||||
LOG(("MaybeCreateTable %s\n", aTableName.get()));
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> createStatement;
|
||||
nsCString statement;
|
||||
statement.Assign("CREATE TABLE IF NOT EXISTS ");
|
||||
statement.Append(aTableName);
|
||||
statement.Append(" (key TEXT PRIMARY KEY, value TEXT)");
|
||||
nsresult rv = mConnection->CreateStatement(statement,
|
||||
getter_AddRefs(createStatement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return createStatement->Execute();
|
||||
}
|
||||
|
||||
void
|
||||
nsUrlClassifierDBServiceWorker::GetDbTableName(const nsACString& aTableName,
|
||||
nsCString* aDbTableName) {
|
||||
aDbTableName->Assign(aTableName);
|
||||
aDbTableName->ReplaceChar('-', '_');
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Proxy class implementation
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsUrlClassifierDBService,
|
||||
nsIUrlClassifierDBService,
|
||||
nsIObserver)
|
||||
|
||||
/* static */ nsUrlClassifierDBService*
|
||||
nsUrlClassifierDBService::GetInstance()
|
||||
{
|
||||
if (!sUrlClassifierDBService) {
|
||||
sUrlClassifierDBService = new nsUrlClassifierDBService();
|
||||
if (!sUrlClassifierDBService)
|
||||
return nsnull;
|
||||
|
||||
NS_ADDREF(sUrlClassifierDBService); // addref the global
|
||||
|
||||
if (NS_FAILED(sUrlClassifierDBService->Init())) {
|
||||
NS_RELEASE(sUrlClassifierDBService);
|
||||
return nsnull;
|
||||
}
|
||||
} else {
|
||||
// Already exists, just add a ref
|
||||
NS_ADDREF(sUrlClassifierDBService); // addref the return result
|
||||
}
|
||||
return sUrlClassifierDBService;
|
||||
}
|
||||
|
||||
|
||||
nsUrlClassifierDBService::nsUrlClassifierDBService()
|
||||
{
|
||||
}
|
||||
|
||||
// Callback functions for event used in destructor.
|
||||
PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *ev);
|
||||
PR_STATIC_CALLBACK(void) DestroyHandler(PLEvent *ev);
|
||||
|
||||
nsUrlClassifierDBService::~nsUrlClassifierDBService()
|
||||
{
|
||||
sUrlClassifierDBService = nsnull;
|
||||
PR_DestroyMonitor(gMonitor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierDBService::Init()
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gUrlClassifierDbServiceLog)
|
||||
gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService");
|
||||
#endif
|
||||
gMonitor = PR_NewMonitor();
|
||||
// Start the background thread.
|
||||
gDbBackgroundThread = PR_CreateThread(PR_USER_THREAD,
|
||||
EventLoop,
|
||||
nsnull,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD,
|
||||
0);
|
||||
if (!gDbBackgroundThread)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mWorker = new nsUrlClassifierDBServiceWorker();
|
||||
if (!mWorker)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Add an observer for shutdown
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (!observerService)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::Exists(const nsACString& tableName,
|
||||
const nsACString& key,
|
||||
nsIUrlClassifierCallback *c)
|
||||
{
|
||||
EnsureThreadStarted();
|
||||
nsresult rv;
|
||||
// The proxy callback uses the current thread.
|
||||
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
||||
rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ,
|
||||
NS_GET_IID(nsIUrlClassifierCallback),
|
||||
c,
|
||||
PROXY_ASYNC,
|
||||
getter_AddRefs(proxyCallback));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The actual worker uses the background thread.
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> proxy;
|
||||
rv = NS_GetProxyForObject(gEventQ,
|
||||
NS_GET_IID(nsIUrlClassifierDBServiceWorker),
|
||||
mWorker,
|
||||
PROXY_ASYNC,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return proxy->Exists(tableName, key, proxyCallback);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::UpdateTables(const nsACString& updateString,
|
||||
nsIUrlClassifierCallback *c)
|
||||
{
|
||||
EnsureThreadStarted();
|
||||
nsresult rv;
|
||||
// The proxy callback uses the current thread.
|
||||
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
||||
rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ,
|
||||
NS_GET_IID(nsIUrlClassifierCallback),
|
||||
c,
|
||||
PROXY_ASYNC,
|
||||
getter_AddRefs(proxyCallback));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The actual worker uses the background thread.
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> proxy;
|
||||
rv = NS_GetProxyForObject(gEventQ,
|
||||
NS_GET_IID(nsIUrlClassifierDBServiceWorker),
|
||||
mWorker,
|
||||
PROXY_ASYNC,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return proxy->UpdateTables(updateString, proxyCallback);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||
Shutdown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Make sure the event queue is intialized before we use it.
|
||||
void
|
||||
nsUrlClassifierDBService::EnsureThreadStarted()
|
||||
{
|
||||
nsAutoMonitor mon(gMonitor);
|
||||
while (!gEventQ)
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
// Join the background thread if it exists.
|
||||
nsresult
|
||||
nsUrlClassifierDBService::Shutdown()
|
||||
{
|
||||
// First close the db connection.
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> proxy;
|
||||
nsresult rv = NS_GetProxyForObject(gEventQ,
|
||||
NS_GET_IID(nsIUrlClassifierDBServiceWorker),
|
||||
mWorker,
|
||||
PROXY_ASYNC,
|
||||
getter_AddRefs(proxy));
|
||||
proxy->CloseDb();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PLEvent* ev = new PLEvent;
|
||||
PL_InitEvent(ev, nsnull, EventHandler, DestroyHandler);
|
||||
|
||||
if (NS_FAILED(gEventQ->PostEvent(ev))) {
|
||||
PL_DestroyEvent(ev);
|
||||
}
|
||||
LOG(("joining background thread"));
|
||||
|
||||
PR_JoinThread(gDbBackgroundThread);
|
||||
gDbBackgroundThread = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void)
|
||||
EventLoop(void *arg)
|
||||
{
|
||||
nsresult rv;
|
||||
//LOG(("Starting background thread.\n"));
|
||||
|
||||
nsCOMPtr<nsIEventQueueService> eventQService =
|
||||
do_GetService(kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "do_GetService(EventQueueService)");
|
||||
|
||||
rv = eventQService->CreateMonitoredThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "CreateMonitoredThreadEventQueue");
|
||||
|
||||
{
|
||||
nsAutoMonitor mon(gMonitor);
|
||||
rv = eventQService->GetSpecialEventQueue(
|
||||
nsIEventQueueService::CURRENT_THREAD_EVENT_QUEUE,
|
||||
&gEventQ);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "GetSpecialEventQueue");
|
||||
|
||||
PR_Notify(gMonitor);
|
||||
}
|
||||
|
||||
while (gKeepRunning) {
|
||||
PLEvent* ev;
|
||||
if (NS_SUCCEEDED(gEventQ->WaitForEvent(&ev))) {
|
||||
gEventQ->HandleEvent(ev);
|
||||
}
|
||||
}
|
||||
// It's ok to miss pending events, we'll get them during the next update.
|
||||
|
||||
LOG(("Exiting background thread.\n"));
|
||||
}
|
||||
|
||||
// Shutdown event
|
||||
PR_STATIC_CALLBACK(void *)
|
||||
EventHandler(PLEvent *ev)
|
||||
{
|
||||
gKeepRunning = PR_FALSE;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Clean up shutdown event
|
||||
PR_STATIC_CALLBACK(void)
|
||||
DestroyHandler(PLEvent *ev)
|
||||
{
|
||||
delete ev;
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-/
|
||||
/* ***** 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 <tony@ponderer.org> (original author)
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef nsUrlClassifierDBService_h_
|
||||
#define nsUrlClassifierDBService_h_
|
||||
|
||||
#include <nsISupportsUtils.h>
|
||||
|
||||
#include "nsID.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIUrlClassifierDBService.h"
|
||||
|
||||
class nsUrlClassifierDBServiceWorker;
|
||||
|
||||
// This is a proxy class that just creates a background thread and delagates
|
||||
// calls to the background thread.
|
||||
class nsUrlClassifierDBService : public nsIUrlClassifierDBService,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
// This is thread safe. It throws an exception if the thread is busy.
|
||||
nsUrlClassifierDBService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
static nsUrlClassifierDBService* GetInstance();
|
||||
|
||||
#ifdef MOZILLA_1_8_BRANCH
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_URLCLASSIFIERDBSERVICE_CID)
|
||||
#else
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_URLCLASSIFIERDBSERVICE_CID)
|
||||
#endif
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIURLCLASSIFIERDBSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
// No subclassing
|
||||
~nsUrlClassifierDBService();
|
||||
|
||||
// Disallow copy constructor
|
||||
nsUrlClassifierDBService(nsUrlClassifierDBService&);
|
||||
|
||||
// Make sure the event queue is intialized before we use it.
|
||||
void EnsureThreadStarted();
|
||||
|
||||
// Close db connection and join the background thread if it exists.
|
||||
nsresult Shutdown();
|
||||
|
||||
nsCOMPtr<nsUrlClassifierDBServiceWorker> mWorker;
|
||||
};
|
||||
|
||||
#endif // nsUrlClassifierDBService_h_
|
Loading…
Reference in New Issue
Block a user