2007-03-22 10:30:00 -07:00
|
|
|
//* -*- 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>
|
2007-07-25 23:38:43 -07:00
|
|
|
* Dave Camp <dcamp@mozilla.com>
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* 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 ***** */
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
#include "nsAutoPtr.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "nsCOMPtr.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "mozIStorageService.h"
|
|
|
|
#include "mozIStorageConnection.h"
|
|
|
|
#include "mozIStorageStatement.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "mozStorageHelper.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "mozStorageCID.h"
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
#include "nsAutoLock.h"
|
|
|
|
#include "nsCRT.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "nsICryptoHash.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDirectoryService.h"
|
|
|
|
#include "nsIObserverService.h"
|
2007-08-31 16:18:46 -07:00
|
|
|
#include "nsIPrefBranch.h"
|
|
|
|
#include "nsIPrefBranch2.h"
|
|
|
|
#include "nsIPrefService.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIProperties.h"
|
|
|
|
#include "nsIProxyObjectManager.h"
|
|
|
|
#include "nsToolkitCompsCID.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "nsIUrlClassifierUtils.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsUrlClassifierDBService.h"
|
2007-08-31 16:18:46 -07:00
|
|
|
#include "nsURILoader.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsTArray.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "nsVoidArray.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsNetCID.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsXPCOMStrings.h"
|
|
|
|
#include "prlog.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "prlock.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "prprf.h"
|
2007-07-25 23:38:43 -07:00
|
|
|
#include "zlib.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The DBServices stores a set of Fragments. A fragment is one URL
|
|
|
|
* fragment containing two or more domain components and some number
|
|
|
|
* of path components.
|
|
|
|
*
|
|
|
|
* Fragment examples:
|
|
|
|
* example.com/
|
|
|
|
* www.example.com/foo/bar
|
|
|
|
* www.mail.example.com/mail
|
|
|
|
*
|
|
|
|
* Fragments are described in "Simplified Regular Expression Lookup"
|
|
|
|
* section of the protocol document at
|
|
|
|
* http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec
|
|
|
|
*
|
|
|
|
* A set of fragments is associated with a domain. The domain for a given
|
|
|
|
* fragment is the three-host-component domain of the fragment (two host
|
|
|
|
* components for URLs with only two components) with a trailing slash.
|
|
|
|
* So for the fragments listed above, the domains are example.com/,
|
|
|
|
* www.example.com/ and mail.example.com/. A collection of fragments for
|
|
|
|
* a given domain is referred to in this code as an Entry.
|
|
|
|
*
|
|
|
|
* Entries are associated with the table from which its fragments came.
|
|
|
|
*
|
|
|
|
* Fragments are added to the database in chunks. Each fragment in an entry
|
|
|
|
* keeps track of which chunk it came from, and as a chunk is added it keeps
|
|
|
|
* track of which entries contain its fragments.
|
|
|
|
*
|
|
|
|
* Fragments and domains are hashed in the database. The hash is described
|
|
|
|
* in the protocol document, but it's basically a truncated SHA256 hash.
|
|
|
|
*/
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// NSPR_LOG_MODULES=UrlClassifierDbService:5
|
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
static const PRLogModuleInfo *gUrlClassifierDbServiceLog = nsnull;
|
|
|
|
#define LOG(args) PR_LOG(gUrlClassifierDbServiceLog, PR_LOG_DEBUG, args)
|
2007-07-25 23:38:43 -07:00
|
|
|
#define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierDbServiceLog, 4)
|
2007-03-22 10:30:00 -07:00
|
|
|
#else
|
|
|
|
#define LOG(args)
|
2007-07-25 23:38:43 -07:00
|
|
|
#define LOG_ENABLED() (PR_FALSE)
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Change filename each time we change the db schema.
|
2007-07-25 23:38:43 -07:00
|
|
|
#define DATABASE_FILENAME "urlclassifier3.sqlite"
|
|
|
|
|
|
|
|
#define MAX_HOST_COMPONENTS 5
|
|
|
|
#define MAX_PATH_COMPONENTS 4
|
|
|
|
|
|
|
|
// Updates will fail if fed chunks larger than this
|
|
|
|
#define MAX_CHUNK_SIZE (1024 * 1024)
|
|
|
|
|
|
|
|
#define KEY_LENGTH 16
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
// Prefs for implementing nsIURIClassifier to block page loads
|
|
|
|
#define CHECK_MALWARE_PREF "browser.safebrowsing.malware.enabled"
|
|
|
|
#define CHECK_MALWARE_DEFAULT PR_FALSE
|
|
|
|
|
2007-12-03 21:10:22 -08:00
|
|
|
#define CHECK_PHISHING_PREF "browser.safebrowsing.enabled"
|
|
|
|
#define CHECK_PHISHING_DEFAULT PR_FALSE
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Singleton instance.
|
|
|
|
static nsUrlClassifierDBService* sUrlClassifierDBService;
|
|
|
|
|
|
|
|
// Thread that we do the updates on.
|
|
|
|
static nsIThread* gDbBackgroundThread = nsnull;
|
|
|
|
|
2007-04-24 10:41:44 -07:00
|
|
|
// Once we've committed to shutting down, don't do work in the background
|
|
|
|
// thread.
|
|
|
|
static PRBool gShuttingDownThread = PR_FALSE;
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Hash class implementation
|
|
|
|
|
|
|
|
// A convenience wrapper around the 16-byte hash for a domain or fragment.
|
|
|
|
|
|
|
|
struct nsUrlClassifierHash
|
|
|
|
{
|
|
|
|
PRUint8 buf[KEY_LENGTH];
|
|
|
|
|
|
|
|
nsresult FromPlaintext(const nsACString& plainText, nsICryptoHash *hash);
|
|
|
|
void Assign(const nsACString& str);
|
|
|
|
|
|
|
|
const PRBool operator==(const nsUrlClassifierHash& hash) const {
|
|
|
|
return (memcmp(buf, hash.buf, sizeof(buf)) == 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierHash::FromPlaintext(const nsACString& plainText,
|
|
|
|
nsICryptoHash *hash)
|
|
|
|
{
|
|
|
|
// From the protocol doc:
|
|
|
|
// Each entry in the chunk is composed of the 128 most significant bits
|
|
|
|
// of the SHA 256 hash of a suffix/prefix expression.
|
|
|
|
|
|
|
|
nsresult rv = hash->Init(nsICryptoHash::SHA256);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = hash->Update
|
|
|
|
(reinterpret_cast<const PRUint8*>(plainText.BeginReading()),
|
|
|
|
plainText.Length());
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCAutoString hashed;
|
|
|
|
rv = hash->Finish(PR_FALSE, hashed);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
NS_ASSERTION(hashed.Length() >= KEY_LENGTH,
|
|
|
|
"not enough characters in the hash");
|
|
|
|
|
|
|
|
memcpy(buf, hashed.BeginReading(), KEY_LENGTH);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUrlClassifierHash::Assign(const nsACString& str)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(str.Length() >= KEY_LENGTH,
|
|
|
|
"string must be at least KEY_LENGTH characters long");
|
|
|
|
memcpy(buf, str.BeginReading(), KEY_LENGTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Entry class implementation
|
|
|
|
|
|
|
|
// This class represents one entry in the classifier database. It is a list
|
|
|
|
// of fragments and their associated chunks for a given key/table pair.
|
|
|
|
class nsUrlClassifierEntry
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsUrlClassifierEntry() : mId(0) {}
|
|
|
|
~nsUrlClassifierEntry() {}
|
|
|
|
|
|
|
|
// Read an entry from a database statement
|
|
|
|
PRBool ReadStatement(mozIStorageStatement* statement);
|
|
|
|
|
|
|
|
// Prepare a statement to write this entry to the database
|
|
|
|
nsresult BindStatement(mozIStorageStatement* statement);
|
|
|
|
|
|
|
|
// Add a single fragment associated with a given chunk
|
|
|
|
PRBool AddFragment(const nsUrlClassifierHash& hash, PRUint32 chunkNum);
|
|
|
|
|
|
|
|
// Add all the fragments in a given entry to this entry
|
|
|
|
PRBool Merge(const nsUrlClassifierEntry& entry);
|
|
|
|
|
|
|
|
// Remove all fragments in a given entry from this entry
|
|
|
|
PRBool SubtractFragments(const nsUrlClassifierEntry& entry);
|
|
|
|
|
|
|
|
// Remove all fragments associated with a given chunk
|
|
|
|
PRBool SubtractChunk(PRUint32 chunkNum);
|
|
|
|
|
|
|
|
// Check if there is a fragment with this hash in the entry
|
|
|
|
PRBool HasFragment(const nsUrlClassifierHash& hash);
|
|
|
|
|
|
|
|
// Clear out the entry structure
|
|
|
|
void Clear();
|
|
|
|
|
|
|
|
PRBool IsEmpty() { return mFragments.Length() == 0; }
|
|
|
|
|
|
|
|
nsUrlClassifierHash mKey;
|
|
|
|
PRUint32 mId;
|
|
|
|
PRUint32 mTableId;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Add all the fragments from a database blob
|
|
|
|
PRBool AddFragments(const PRUint8* blob, PRUint32 blobLength);
|
|
|
|
|
|
|
|
// One hash/chunkID pair in the fragment
|
|
|
|
struct Fragment {
|
|
|
|
nsUrlClassifierHash hash;
|
|
|
|
PRUint32 chunkNum;
|
|
|
|
|
|
|
|
PRInt32 Diff(const Fragment& fragment) const {
|
|
|
|
PRInt32 cmp = memcmp(hash.buf, fragment.hash.buf, sizeof(hash.buf));
|
|
|
|
if (cmp != 0) return cmp;
|
|
|
|
return chunkNum - fragment.chunkNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool operator==(const Fragment& fragment) const {
|
|
|
|
return (Diff(fragment) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool operator<(const Fragment& fragment) const {
|
|
|
|
return (Diff(fragment) < 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
nsTArray<Fragment> mFragments;
|
|
|
|
};
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::ReadStatement(mozIStorageStatement* statement)
|
|
|
|
{
|
|
|
|
mId = statement->AsInt32(0);
|
|
|
|
|
|
|
|
PRUint32 size;
|
|
|
|
const PRUint8* blob = statement->AsSharedBlob(1, &size);
|
|
|
|
if (!blob || (size != KEY_LENGTH))
|
|
|
|
return PR_FALSE;
|
|
|
|
memcpy(mKey.buf, blob, KEY_LENGTH);
|
|
|
|
|
|
|
|
blob = statement->AsSharedBlob(2, &size);
|
|
|
|
if (!AddFragments(blob, size))
|
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
mTableId = statement->AsInt32(3);
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierEntry::BindStatement(mozIStorageStatement* statement)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (mId == 0)
|
|
|
|
rv = statement->BindNullParameter(0);
|
|
|
|
else
|
|
|
|
rv = statement->BindInt32Parameter(0, mId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = statement->BindBlobParameter(1, mKey.buf, KEY_LENGTH);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Store the entries as one big blob.
|
|
|
|
// This results in a database that isn't portable between machines.
|
|
|
|
rv = statement->BindBlobParameter
|
|
|
|
(2, reinterpret_cast<PRUint8*>(mFragments.Elements()),
|
|
|
|
mFragments.Length() * sizeof(Fragment));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = statement->BindInt32Parameter(3, mTableId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::AddFragment(const nsUrlClassifierHash& hash,
|
|
|
|
PRUint32 chunkNum)
|
|
|
|
{
|
|
|
|
Fragment* fragment = mFragments.AppendElement();
|
|
|
|
if (!fragment)
|
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
fragment->hash = hash;
|
|
|
|
fragment->chunkNum = chunkNum;
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::AddFragments(const PRUint8* blob, PRUint32 blobLength)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(blobLength % sizeof(Fragment) == 0,
|
|
|
|
"Fragment blob not the right length");
|
|
|
|
Fragment* fragment = mFragments.AppendElements
|
|
|
|
(reinterpret_cast<const Fragment*>(blob), blobLength / sizeof(Fragment));
|
|
|
|
return (fragment != nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::Merge(const nsUrlClassifierEntry& entry)
|
|
|
|
{
|
|
|
|
Fragment* fragment = mFragments.AppendElements(entry.mFragments);
|
|
|
|
return (fragment != nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::SubtractFragments(const nsUrlClassifierEntry& entry)
|
|
|
|
{
|
|
|
|
for (PRUint32 i = 0; i < entry.mFragments.Length(); i++) {
|
|
|
|
for (PRUint32 j = 0; j < mFragments.Length(); j++) {
|
|
|
|
if (mFragments[j].hash == entry.mFragments[i].hash) {
|
|
|
|
mFragments.RemoveElementAt(j);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::SubtractChunk(PRUint32 chunkNum)
|
|
|
|
{
|
|
|
|
PRUint32 i = 0;
|
|
|
|
while (i < mFragments.Length()) {
|
|
|
|
if (mFragments[i].chunkNum == chunkNum)
|
|
|
|
mFragments.RemoveElementAt(i);
|
|
|
|
else
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsUrlClassifierEntry::HasFragment(const nsUrlClassifierHash& hash)
|
|
|
|
{
|
|
|
|
for (PRUint32 i = 0; i < mFragments.Length(); i++) {
|
|
|
|
const Fragment& fragment = mFragments[i];
|
|
|
|
if (fragment.hash == hash)
|
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
return PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
void
|
|
|
|
nsUrlClassifierEntry::Clear()
|
|
|
|
{
|
|
|
|
mId = 0;
|
|
|
|
mFragments.Clear();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Actual worker implemenatation
|
|
|
|
class nsUrlClassifierDBServiceWorker : public nsIUrlClassifierDBServiceWorker
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsUrlClassifierDBServiceWorker();
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIURLCLASSIFIERDBSERVICE
|
|
|
|
NS_DECL_NSIURLCLASSIFIERDBSERVICEWORKER
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Initialize, called in the main thread
|
|
|
|
nsresult Init();
|
|
|
|
|
|
|
|
// Queue a lookup for the worker to perform, called in the main thread.
|
|
|
|
nsresult QueueLookup(const nsACString& lookupKey,
|
|
|
|
nsIUrlClassifierCallback* callback);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
private:
|
|
|
|
// No subclassing
|
|
|
|
~nsUrlClassifierDBServiceWorker();
|
|
|
|
|
|
|
|
// Disallow copy constructor
|
|
|
|
nsUrlClassifierDBServiceWorker(nsUrlClassifierDBServiceWorker&);
|
|
|
|
|
|
|
|
// Try to open the db, DATABASE_FILENAME.
|
|
|
|
nsresult OpenDb();
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Create table in the db if they don't exist.
|
|
|
|
nsresult MaybeCreateTables(mozIStorageConnection* connection);
|
|
|
|
|
|
|
|
nsresult GetTableName(PRUint32 tableId, nsACString& table);
|
|
|
|
nsresult GetTableId(const nsACString& table, PRUint32* tableId);
|
|
|
|
|
|
|
|
// Read the entry for a given key/table from the database
|
|
|
|
nsresult ReadEntry(const nsUrlClassifierHash& key,
|
|
|
|
PRUint32 tableId,
|
|
|
|
nsUrlClassifierEntry& entry);
|
|
|
|
|
|
|
|
// Read the entry with a given ID from the database
|
|
|
|
nsresult ReadEntry(PRUint32 id, nsUrlClassifierEntry& entry);
|
|
|
|
|
|
|
|
// Remove an entry from the database
|
|
|
|
nsresult DeleteEntry(nsUrlClassifierEntry& entry);
|
|
|
|
|
|
|
|
// Write an entry to the database
|
|
|
|
nsresult WriteEntry(nsUrlClassifierEntry& entry);
|
|
|
|
|
|
|
|
// Decompress a zlib'ed chunk (used for -exp tables)
|
|
|
|
nsresult InflateChunk(nsACString& chunk);
|
|
|
|
|
|
|
|
// Expand a chunk into its individual entries
|
|
|
|
nsresult GetChunkEntries(const nsACString& table,
|
|
|
|
PRUint32 tableId,
|
|
|
|
PRUint32 chunkNum,
|
|
|
|
nsACString& chunk,
|
|
|
|
nsTArray<nsUrlClassifierEntry>& entries);
|
|
|
|
|
|
|
|
// Expand a stringified chunk list into an array of ints.
|
|
|
|
nsresult ParseChunkList(const nsACString& chunkStr,
|
|
|
|
nsTArray<PRUint32>& chunks);
|
|
|
|
|
|
|
|
// Join an array of ints into a stringified chunk list.
|
|
|
|
nsresult JoinChunkList(nsTArray<PRUint32>& chunks, nsCString& chunkStr);
|
|
|
|
|
|
|
|
// List the add/subtract chunks that have been applied to a table
|
|
|
|
nsresult GetChunkLists(PRUint32 tableId,
|
|
|
|
nsACString& addChunks,
|
|
|
|
nsACString& subChunks);
|
|
|
|
|
|
|
|
// Set the list of add/subtract chunks that have been applied to a table
|
|
|
|
nsresult SetChunkLists(PRUint32 tableId,
|
|
|
|
const nsACString& addChunks,
|
|
|
|
const nsACString& subChunks);
|
|
|
|
|
2007-12-03 20:49:22 -08:00
|
|
|
// Cache the list of add/subtract chunks applied to the table, optionally
|
|
|
|
// parsing the add or sub lists. These lists are cached while updating
|
|
|
|
// tables to avoid excessive database reads/writes and parsing.
|
|
|
|
nsresult CacheChunkLists(PRUint32 tableId,
|
|
|
|
PRBool parseAdds,
|
|
|
|
PRBool parseSubs);
|
|
|
|
// Flush the cached add/subtract lists to the database.
|
|
|
|
nsresult FlushChunkLists();
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Add a list of entries to the database, merging with
|
|
|
|
// existing entries as necessary
|
|
|
|
nsresult AddChunk(PRUint32 tableId, PRUint32 chunkNum,
|
|
|
|
nsTArray<nsUrlClassifierEntry>& entries);
|
|
|
|
|
|
|
|
// Expire an add chunk
|
|
|
|
nsresult ExpireAdd(PRUint32 tableId, PRUint32 chunkNum);
|
|
|
|
|
|
|
|
// Subtract a list of entries from the database
|
|
|
|
nsresult SubChunk(PRUint32 tableId, PRUint32 chunkNum,
|
|
|
|
nsTArray<nsUrlClassifierEntry>& entries);
|
|
|
|
|
|
|
|
// Expire a subtract chunk
|
|
|
|
nsresult ExpireSub(PRUint32 tableId, PRUint32 chunkNum);
|
|
|
|
|
|
|
|
// Handle line-oriented control information from a stream update
|
|
|
|
nsresult ProcessResponseLines(PRBool* done);
|
|
|
|
// Handle chunk data from a stream update
|
|
|
|
nsresult ProcessChunk(PRBool* done);
|
|
|
|
|
|
|
|
// Reset an in-progress update
|
|
|
|
void ResetUpdate();
|
|
|
|
|
|
|
|
// take a lookup string (www.hostname.com/path/to/resource.html) and
|
|
|
|
// expand it into the set of fragments that should be searched for in an
|
|
|
|
// entry
|
|
|
|
nsresult GetLookupFragments(const nsCSubstring& spec,
|
|
|
|
nsTArray<nsUrlClassifierHash>& fragments);
|
|
|
|
|
2007-10-01 17:21:45 -07:00
|
|
|
// Check for a canonicalized IP address.
|
|
|
|
PRBool IsCanonicalizedIP(const nsACString& host);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Get the database key for a given URI. This is the top three
|
|
|
|
// domain components if they exist, otherwise the top two.
|
2007-10-01 17:21:45 -07:00
|
|
|
// hostname.com/foo/bar -> hostname.com
|
2007-07-25 23:38:43 -07:00
|
|
|
// mail.hostname.com/foo/bar -> mail.hostname.com
|
|
|
|
// www.mail.hostname.com/foo/bar -> mail.hostname.com
|
|
|
|
nsresult GetKey(const nsACString& spec, nsUrlClassifierHash& hash);
|
|
|
|
|
|
|
|
// Look for a given lookup string (www.hostname.com/path/to/resource.html)
|
|
|
|
// in the entries at the given key. Return the tableids found.
|
|
|
|
nsresult CheckKey(const nsCSubstring& spec,
|
|
|
|
const nsUrlClassifierHash& key,
|
|
|
|
nsTArray<PRUint32>& tables);
|
|
|
|
|
|
|
|
// Perform a classifier lookup for a given url.
|
|
|
|
nsresult DoLookup(const nsACString& spec, nsIUrlClassifierCallback* c);
|
|
|
|
|
|
|
|
// Handle any queued-up lookups. We call this function during long-running
|
|
|
|
// update operations to prevent lookups from blocking for too long.
|
|
|
|
nsresult HandlePendingLookups();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> mDBFile;
|
|
|
|
|
|
|
|
nsCOMPtr<nsICryptoHash> mCryptoHash;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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).
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCOMPtr<mozIStorageConnection> mConnection;
|
|
|
|
|
|
|
|
nsCOMPtr<mozIStorageStatement> mLookupStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mLookupWithTableStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mLookupWithIDStatement;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCOMPtr<mozIStorageStatement> mUpdateStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mDeleteStatement;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCOMPtr<mozIStorageStatement> mAddChunkEntriesStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mGetChunkEntriesStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mDeleteChunkEntriesStatement;
|
|
|
|
|
|
|
|
nsCOMPtr<mozIStorageStatement> mGetChunkListsStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mSetChunkListsStatement;
|
|
|
|
|
|
|
|
nsCOMPtr<mozIStorageStatement> mGetTablesStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mGetTableIdStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mGetTableNameStatement;
|
|
|
|
nsCOMPtr<mozIStorageStatement> mInsertTableIdStatement;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// We receive data in small chunks that may be broken in the middle of
|
|
|
|
// a line. So we save the last partial line here.
|
|
|
|
nsCString mPendingStreamUpdate;
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
PRInt32 mUpdateWait;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
STATE_LINE,
|
|
|
|
STATE_CHUNK
|
|
|
|
} mState;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
CHUNK_ADD,
|
|
|
|
CHUNK_SUB
|
|
|
|
} mChunkType;
|
|
|
|
|
|
|
|
PRUint32 mChunkNum;
|
|
|
|
PRUint32 mChunkLen;
|
|
|
|
|
|
|
|
nsCString mUpdateTable;
|
|
|
|
PRUint32 mUpdateTableId;
|
|
|
|
|
|
|
|
nsresult mUpdateStatus;
|
|
|
|
|
2007-12-03 20:49:22 -08:00
|
|
|
PRBool mHaveCachedLists;
|
|
|
|
PRUint32 mCachedListsTable;
|
|
|
|
nsCAutoString mCachedSubsStr;
|
|
|
|
nsCAutoString mCachedAddsStr;
|
|
|
|
|
|
|
|
PRBool mHaveCachedAddChunks;
|
|
|
|
nsTArray<PRUint32> mCachedAddChunks;
|
|
|
|
|
|
|
|
PRBool mHaveCachedSubChunks;
|
|
|
|
nsTArray<PRUint32> mCachedSubChunks;
|
|
|
|
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Pending lookups are stored in a queue for processing. The queue
|
|
|
|
// is protected by mPendingLookupLock.
|
|
|
|
PRLock* mPendingLookupLock;
|
|
|
|
|
|
|
|
class PendingLookup {
|
|
|
|
public:
|
|
|
|
nsCString mKey;
|
|
|
|
nsCOMPtr<nsIUrlClassifierCallback> mCallback;
|
|
|
|
};
|
|
|
|
|
|
|
|
// list of pending lookups
|
|
|
|
nsTArray<PendingLookup> mPendingLookups;
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierDBServiceWorker,
|
|
|
|
nsIUrlClassifierDBServiceWorker)
|
|
|
|
|
|
|
|
nsUrlClassifierDBServiceWorker::nsUrlClassifierDBServiceWorker()
|
2007-07-25 23:38:43 -07:00
|
|
|
: mUpdateStatus(NS_OK)
|
2007-12-03 20:49:22 -08:00
|
|
|
, mHaveCachedLists(PR_FALSE)
|
|
|
|
, mCachedListsTable(PR_UINT32_MAX)
|
2007-07-25 23:38:43 -07:00
|
|
|
, mPendingLookupLock(nsnull)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsUrlClassifierDBServiceWorker::~nsUrlClassifierDBServiceWorker()
|
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ASSERTION(!mConnection,
|
2007-03-22 10:30:00 -07:00
|
|
|
"Db connection not closed, leaking memory! Call CloseDb "
|
|
|
|
"to close the connection.");
|
2007-07-25 23:38:43 -07:00
|
|
|
if (mPendingLookupLock)
|
|
|
|
PR_DestroyLock(mPendingLookupLock);
|
2007-07-25 20:11:43 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::Init()
|
|
|
|
{
|
|
|
|
// Compute database filename
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Because we dump raw integers into the database, this database isn't
|
|
|
|
// portable between machine types, so store it in the local profile dir.
|
|
|
|
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
|
|
|
|
getter_AddRefs(mDBFile));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
rv = mDBFile->Append(NS_LITERAL_STRING(DATABASE_FILENAME));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mPendingLookupLock = PR_NewLock();
|
|
|
|
if (!mPendingLookupLock)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
ResetUpdate();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::QueueLookup(const nsACString& spec,
|
|
|
|
nsIUrlClassifierCallback* callback)
|
2007-07-25 20:11:43 -07:00
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
nsAutoLock lock(mPendingLookupLock);
|
|
|
|
|
|
|
|
PendingLookup* lookup = mPendingLookups.AppendElement();
|
|
|
|
if (!lookup) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
lookup->mKey = spec;
|
|
|
|
lookup->mCallback = callback;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::GetLookupFragments(const nsACString& spec,
|
|
|
|
nsTArray<nsUrlClassifierHash>& fragments)
|
|
|
|
{
|
|
|
|
fragments.Clear();
|
|
|
|
|
|
|
|
nsACString::const_iterator begin, end, iter;
|
|
|
|
spec.BeginReading(begin);
|
|
|
|
spec.EndReading(end);
|
|
|
|
|
|
|
|
iter = begin;
|
|
|
|
if (!FindCharInReadable('/', iter, end)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsCSubstring& host = Substring(begin, iter++);
|
2007-10-01 16:53:53 -07:00
|
|
|
nsCAutoString path;
|
|
|
|
path.Assign(Substring(iter, end));
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* From the protocol doc:
|
2007-10-01 16:53:53 -07:00
|
|
|
* For the hostname, the client will try at most 5 different strings. They
|
2007-07-25 23:38:43 -07:00
|
|
|
* are:
|
|
|
|
* a) The exact hostname of the url
|
|
|
|
* b) The 4 hostnames formed by starting with the last 5 components and
|
|
|
|
* successivly removing the leading component. The top-level component
|
|
|
|
* can be skipped.
|
|
|
|
*/
|
2007-11-13 21:31:07 -08:00
|
|
|
nsCStringArray hosts;
|
|
|
|
hosts.AppendCString(host);
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
host.BeginReading(begin);
|
|
|
|
host.EndReading(end);
|
|
|
|
int numComponents = 0;
|
|
|
|
while (RFindInReadable(NS_LITERAL_CSTRING("."), begin, end) &&
|
|
|
|
numComponents < MAX_HOST_COMPONENTS) {
|
|
|
|
// don't bother checking toplevel domains
|
|
|
|
if (++numComponents >= 2) {
|
|
|
|
host.EndReading(iter);
|
2007-11-13 21:31:07 -08:00
|
|
|
hosts.AppendCString(Substring(end, iter));
|
2007-07-25 23:38:43 -07:00
|
|
|
}
|
|
|
|
end = begin;
|
|
|
|
host.BeginReading(begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* From the protocol doc:
|
2007-10-01 16:53:53 -07:00
|
|
|
* For the path, the client will also try at most 6 different strings.
|
2007-07-25 23:38:43 -07:00
|
|
|
* They are:
|
2007-10-01 16:53:53 -07:00
|
|
|
* a) the exact path of the url, including query parameters
|
|
|
|
* b) the exact path of the url, without query parameters
|
|
|
|
* c) the 4 paths formed by starting at the root (/) and
|
2007-07-25 23:38:43 -07:00
|
|
|
* successively appending path components, including a trailing
|
|
|
|
* slash. This behavior should only extend up to the next-to-last
|
|
|
|
* path component, that is, a trailing slash should never be
|
|
|
|
* appended that was not present in the original url.
|
|
|
|
*/
|
2007-11-13 21:31:07 -08:00
|
|
|
nsCStringArray paths;
|
|
|
|
paths.AppendCString(path);
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-10-01 16:53:53 -07:00
|
|
|
path.BeginReading(iter);
|
|
|
|
path.EndReading(end);
|
|
|
|
if (FindCharInReadable('?', iter, end)) {
|
|
|
|
path.BeginReading(begin);
|
|
|
|
path = Substring(begin, iter);
|
2007-11-13 21:31:07 -08:00
|
|
|
paths.AppendCString(path);
|
2007-10-01 16:53:53 -07:00
|
|
|
}
|
|
|
|
|
2007-11-05 11:31:55 -08:00
|
|
|
// Check an empty path (for whole-domain blacklist entries)
|
2007-11-13 21:31:07 -08:00
|
|
|
paths.AppendCString(EmptyCString());
|
2007-11-05 11:31:55 -08:00
|
|
|
|
|
|
|
numComponents = 1;
|
2007-07-25 23:38:43 -07:00
|
|
|
path.BeginReading(begin);
|
|
|
|
path.EndReading(end);
|
|
|
|
iter = begin;
|
|
|
|
while (FindCharInReadable('/', iter, end) &&
|
|
|
|
numComponents < MAX_PATH_COMPONENTS) {
|
|
|
|
iter++;
|
2007-11-13 21:31:07 -08:00
|
|
|
paths.AppendCString(Substring(begin, iter));
|
2007-07-25 23:38:43 -07:00
|
|
|
numComponents++;
|
|
|
|
}
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
for (int hostIndex = 0; hostIndex < hosts.Count(); hostIndex++) {
|
|
|
|
for (int pathIndex = 0; pathIndex < paths.Count(); pathIndex++) {
|
2007-10-01 16:53:53 -07:00
|
|
|
nsCAutoString key;
|
2007-11-13 21:31:07 -08:00
|
|
|
key.Assign(*hosts[hostIndex]);
|
2007-07-25 23:38:43 -07:00
|
|
|
key.Append('/');
|
2007-11-13 21:31:07 -08:00
|
|
|
key.Append(*paths[pathIndex]);
|
2007-07-25 23:38:43 -07:00
|
|
|
LOG(("Chking %s", key.get()));
|
|
|
|
|
2007-10-01 16:53:53 -07:00
|
|
|
nsUrlClassifierHash* hash = fragments.AppendElement();
|
2007-07-25 23:38:43 -07:00
|
|
|
if (!hash) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
hash->FromPlaintext(key, mCryptoHash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::CheckKey(const nsACString& spec,
|
|
|
|
const nsUrlClassifierHash& hash,
|
|
|
|
nsTArray<PRUint32>& tables)
|
|
|
|
{
|
|
|
|
mozStorageStatementScoper lookupScoper(mLookupStatement);
|
|
|
|
|
|
|
|
nsresult rv = mLookupStatement->BindBlobParameter
|
|
|
|
(0, hash.buf, KEY_LENGTH);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsTArray<nsUrlClassifierHash> fragments;
|
|
|
|
PRBool haveFragments = PR_FALSE;
|
|
|
|
|
|
|
|
PRBool exists;
|
|
|
|
rv = mLookupStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
while (exists) {
|
|
|
|
if (!haveFragments) {
|
|
|
|
rv = GetLookupFragments(spec, fragments);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
haveFragments = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsUrlClassifierEntry entry;
|
|
|
|
if (!entry.ReadStatement(mLookupStatement))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < fragments.Length(); i++) {
|
|
|
|
if (entry.HasFragment(fragments[i])) {
|
|
|
|
tables.AppendElement(entry.mTableId);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = mLookupStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lookup up a key in the database is a two step process:
|
|
|
|
*
|
|
|
|
* a) First we look for any Entries in the database that might apply to this
|
|
|
|
* url. For each URL there are one or two possible domain names to check:
|
|
|
|
* the two-part domain name (example.com) and the three-part name
|
|
|
|
* (www.example.com). We check the database for both of these.
|
|
|
|
* b) If we find any entries, we check the list of fragments for that entry
|
|
|
|
* against the possible subfragments of the URL as described in the
|
|
|
|
* "Simplified Regular Expression Lookup" section of the protocol doc.
|
|
|
|
*/
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::DoLookup(const nsACString& spec,
|
|
|
|
nsIUrlClassifierCallback* c)
|
|
|
|
{
|
|
|
|
if (gShuttingDownThread) {
|
|
|
|
c->HandleEvent(EmptyCString());
|
2007-07-25 20:11:43 -07:00
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
2007-07-25 23:38:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = OpenDb();
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
c->HandleEvent(EmptyCString());
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
PRIntervalTime clockStart = 0;
|
|
|
|
if (LOG_ENABLED()) {
|
|
|
|
clockStart = PR_IntervalNow();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsACString::const_iterator begin, end, iter;
|
|
|
|
spec.BeginReading(begin);
|
|
|
|
spec.EndReading(end);
|
|
|
|
|
|
|
|
iter = begin;
|
|
|
|
if (!FindCharInReadable('/', iter, end)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsCSubstring& host = Substring(begin, iter++);
|
|
|
|
|
2007-10-01 17:21:45 -07:00
|
|
|
nsTArray<PRUint32> resultTables;
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierHash hash;
|
|
|
|
|
2007-10-01 17:21:45 -07:00
|
|
|
if (IsCanonicalizedIP(host)) {
|
|
|
|
// Don't break up the host into components
|
|
|
|
hash.FromPlaintext(host, mCryptoHash);
|
|
|
|
CheckKey(spec, hash, resultTables);
|
|
|
|
} else {
|
2007-11-13 21:31:07 -08:00
|
|
|
nsCStringArray hostComponents;
|
|
|
|
hostComponents.ParseString(PromiseFlatCString(host).get(), ".");
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
if (hostComponents.Count() < 2) {
|
2007-10-01 17:21:45 -07:00
|
|
|
// no host or toplevel host, this won't match anything in the db
|
|
|
|
c->HandleEvent(EmptyCString());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First check with two domain components
|
2007-11-13 21:31:07 -08:00
|
|
|
PRInt32 last = hostComponents.Count() - 1;
|
2007-10-01 17:21:45 -07:00
|
|
|
nsCAutoString lookupHost;
|
2007-11-13 21:31:07 -08:00
|
|
|
lookupHost.Assign(*hostComponents[last - 1]);
|
2007-10-01 17:21:45 -07:00
|
|
|
lookupHost.Append(".");
|
2007-11-13 21:31:07 -08:00
|
|
|
lookupHost.Append(*hostComponents[last]);
|
2007-10-01 17:21:45 -07:00
|
|
|
lookupHost.Append("/");
|
|
|
|
hash.FromPlaintext(lookupHost, mCryptoHash);
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-10-01 17:21:45 -07:00
|
|
|
// we ignore failures from CheckKey because we'd rather try to find
|
|
|
|
// more results than fail.
|
2007-07-25 23:38:43 -07:00
|
|
|
CheckKey(spec, hash, resultTables);
|
2007-10-01 17:21:45 -07:00
|
|
|
|
|
|
|
// Now check with three domain components
|
2007-11-13 21:31:07 -08:00
|
|
|
if (hostComponents.Count() > 2) {
|
2007-10-01 17:21:45 -07:00
|
|
|
nsCAutoString lookupHost2;
|
2007-11-13 21:31:07 -08:00
|
|
|
lookupHost2.Assign(*hostComponents[last - 2]);
|
2007-10-01 17:21:45 -07:00
|
|
|
lookupHost2.Append(".");
|
|
|
|
lookupHost2.Append(lookupHost);
|
|
|
|
hash.FromPlaintext(lookupHost2, mCryptoHash);
|
|
|
|
|
|
|
|
CheckKey(spec, hash, resultTables);
|
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCAutoString result;
|
|
|
|
for (PRUint32 i = 0; i < resultTables.Length(); i++) {
|
|
|
|
nsCAutoString tableName;
|
|
|
|
GetTableName(resultTables[i], tableName);
|
|
|
|
|
|
|
|
// ignore GetTableName failures - we want to try to get as many of the
|
|
|
|
// matched tables as possible
|
|
|
|
if (!result.IsEmpty()) {
|
|
|
|
result.Append(',');
|
|
|
|
}
|
|
|
|
result.Append(tableName);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
if (LOG_ENABLED()) {
|
|
|
|
PRIntervalTime clockEnd = PR_IntervalNow();
|
|
|
|
LOG(("query took %dms\n",
|
|
|
|
PR_IntervalToMilliseconds(clockEnd - clockStart)));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
c->HandleEvent(result);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::HandlePendingLookups()
|
|
|
|
{
|
|
|
|
nsAutoLock lock(mPendingLookupLock);
|
|
|
|
while (mPendingLookups.Length() > 0) {
|
|
|
|
PendingLookup lookup = mPendingLookups[0];
|
|
|
|
mPendingLookups.RemoveElementAt(0);
|
|
|
|
lock.unlock();
|
|
|
|
|
|
|
|
DoLookup(lookup.mKey, lookup.mCallback);
|
|
|
|
|
|
|
|
lock.lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup a key in the db.
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBServiceWorker::Lookup(const nsACString& spec,
|
|
|
|
nsIUrlClassifierCallback* c,
|
|
|
|
PRBool needsProxy)
|
|
|
|
{
|
|
|
|
return HandlePendingLookups();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBServiceWorker::GetTables(nsIUrlClassifierCallback* c)
|
|
|
|
{
|
|
|
|
if (gShuttingDownThread)
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
|
|
|
|
nsresult rv = OpenDb();
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_ERROR("Unable to open database");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mozStorageStatementScoper scoper(mGetTablesStatement);
|
|
|
|
|
|
|
|
nsCAutoString response;
|
|
|
|
PRBool hasMore;
|
|
|
|
while (NS_SUCCEEDED(rv = mGetTablesStatement->ExecuteStep(&hasMore)) &&
|
|
|
|
hasMore) {
|
|
|
|
nsCAutoString val;
|
|
|
|
mGetTablesStatement->GetUTF8String(0, val);
|
|
|
|
|
|
|
|
if (val.IsEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Append(val);
|
|
|
|
response.Append(';');
|
|
|
|
|
|
|
|
mGetTablesStatement->GetUTF8String(1, val);
|
|
|
|
|
2007-10-11 16:25:10 -07:00
|
|
|
PRBool haveAdds = PR_FALSE;
|
2007-07-25 23:38:43 -07:00
|
|
|
if (!val.IsEmpty()) {
|
|
|
|
response.Append("a:");
|
|
|
|
response.Append(val);
|
2007-10-11 16:25:10 -07:00
|
|
|
haveAdds = PR_TRUE;
|
2007-07-25 23:38:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mGetTablesStatement->GetUTF8String(2, val);
|
|
|
|
if (!val.IsEmpty()) {
|
2007-10-11 16:25:10 -07:00
|
|
|
if (haveAdds)
|
|
|
|
response.Append(":");
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
response.Append("s:");
|
|
|
|
response.Append(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
response.Append('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
response.Truncate();
|
|
|
|
}
|
|
|
|
|
|
|
|
c->HandleEvent(response);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::GetTableId(const nsACString& table,
|
|
|
|
PRUint32* tableId)
|
|
|
|
{
|
|
|
|
mozStorageStatementScoper findScoper(mGetTableIdStatement);
|
|
|
|
|
|
|
|
nsresult rv = mGetTableIdStatement->BindUTF8StringParameter(0, table);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool exists;
|
|
|
|
rv = mGetTableIdStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (exists) {
|
|
|
|
*tableId = mGetTableIdStatement->AsInt32(0);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
mozStorageStatementScoper insertScoper(mInsertTableIdStatement);
|
|
|
|
rv = mInsertTableIdStatement->BindUTF8StringParameter(0, table);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = mInsertTableIdStatement->Execute();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRInt64 rowId;
|
|
|
|
rv = mConnection->GetLastInsertRowID(&rowId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (rowId > PR_UINT32_MAX)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
*tableId = rowId;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::GetTableName(PRUint32 tableId,
|
|
|
|
nsACString& tableName)
|
|
|
|
{
|
|
|
|
mozStorageStatementScoper findScoper(mGetTableNameStatement);
|
|
|
|
nsresult rv = mGetTableNameStatement->BindInt32Parameter(0, tableId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool exists;
|
|
|
|
rv = mGetTableNameStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!exists) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return mGetTableNameStatement->GetUTF8String(0, tableName);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::InflateChunk(nsACString& chunk)
|
|
|
|
{
|
|
|
|
nsCAutoString inflated;
|
|
|
|
char buf[4096];
|
|
|
|
|
|
|
|
const nsPromiseFlatCString& flat = PromiseFlatCString(chunk);
|
|
|
|
|
|
|
|
z_stream stream;
|
|
|
|
memset(&stream, 0, sizeof(stream));
|
|
|
|
stream.next_in = (Bytef*)flat.get();
|
|
|
|
stream.avail_in = flat.Length();
|
|
|
|
|
|
|
|
if (inflateInit(&stream) != Z_OK) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int code;
|
|
|
|
do {
|
|
|
|
stream.next_out = (Bytef*)buf;
|
|
|
|
stream.avail_out = sizeof(buf);
|
|
|
|
|
|
|
|
code = inflate(&stream, Z_NO_FLUSH);
|
|
|
|
PRUint32 numRead = sizeof(buf) - stream.avail_out;
|
|
|
|
|
|
|
|
if (code == Z_OK || code == Z_STREAM_END) {
|
|
|
|
inflated.Append(buf, numRead);
|
|
|
|
}
|
|
|
|
} while (code == Z_OK);
|
|
|
|
|
|
|
|
inflateEnd(&stream);
|
|
|
|
|
|
|
|
if (code != Z_STREAM_END) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
chunk = inflated;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ReadEntry(const nsUrlClassifierHash& hash,
|
|
|
|
PRUint32 tableId,
|
|
|
|
nsUrlClassifierEntry& entry)
|
|
|
|
{
|
|
|
|
entry.Clear();
|
|
|
|
|
|
|
|
mozStorageStatementScoper scoper(mLookupWithTableStatement);
|
|
|
|
|
|
|
|
nsresult rv = mLookupWithTableStatement->BindBlobParameter
|
|
|
|
(0, hash.buf, KEY_LENGTH);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = mLookupWithTableStatement->BindInt32Parameter(1, tableId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool exists;
|
|
|
|
rv = mLookupWithTableStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (exists) {
|
|
|
|
if (!entry.ReadStatement(mLookupWithTableStatement))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
} else {
|
|
|
|
// New entry, initialize it
|
|
|
|
entry.mKey = hash;
|
|
|
|
entry.mTableId = tableId;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ReadEntry(PRUint32 id,
|
|
|
|
nsUrlClassifierEntry& entry)
|
|
|
|
{
|
|
|
|
entry.Clear();
|
|
|
|
entry.mId = id;
|
|
|
|
|
|
|
|
mozStorageStatementScoper scoper(mLookupWithIDStatement);
|
|
|
|
|
|
|
|
nsresult rv = mLookupWithIDStatement->BindInt32Parameter(0, id);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = mLookupWithIDStatement->BindInt32Parameter(0, id);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool exists;
|
|
|
|
rv = mLookupWithIDStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (exists) {
|
|
|
|
if (!entry.ReadStatement(mLookupWithIDStatement))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::DeleteEntry(nsUrlClassifierEntry& entry)
|
|
|
|
{
|
|
|
|
if (entry.mId == 0) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
mozStorageStatementScoper scoper(mDeleteStatement);
|
|
|
|
mDeleteStatement->BindInt32Parameter(0, entry.mId);
|
|
|
|
nsresult rv = mDeleteStatement->Execute();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
entry.mId = 0;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::WriteEntry(nsUrlClassifierEntry& entry)
|
|
|
|
{
|
|
|
|
mozStorageStatementScoper scoper(mUpdateStatement);
|
|
|
|
|
|
|
|
if (entry.IsEmpty()) {
|
|
|
|
return DeleteEntry(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool newEntry = (entry.mId == 0);
|
|
|
|
|
|
|
|
nsresult rv = entry.BindStatement(mUpdateStatement);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = mUpdateStatement->Execute();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (newEntry) {
|
|
|
|
PRInt64 rowId;
|
|
|
|
rv = mConnection->GetLastInsertRowID(&rowId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (rowId > PR_UINT32_MAX) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.mId = rowId;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-10-01 17:21:45 -07:00
|
|
|
PRBool
|
|
|
|
nsUrlClassifierDBServiceWorker::IsCanonicalizedIP(const nsACString& host)
|
|
|
|
{
|
|
|
|
// The canonicalization process will have left IP addresses in dotted
|
|
|
|
// decimal with no surprises.
|
|
|
|
PRUint32 i1, i2, i3, i4;
|
|
|
|
char c;
|
|
|
|
if (PR_sscanf(PromiseFlatCString(host).get(), "%u.%u.%u.%u%c",
|
|
|
|
&i1, &i2, &i3, &i4, &c) == 4) {
|
|
|
|
return (i1 <= 0xFF && i1 <= 0xFF && i1 <= 0xFF && i1 <= 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::GetKey(const nsACString& spec,
|
|
|
|
nsUrlClassifierHash& hash)
|
|
|
|
{
|
|
|
|
nsACString::const_iterator begin, end, iter;
|
|
|
|
spec.BeginReading(begin);
|
|
|
|
spec.EndReading(end);
|
|
|
|
|
|
|
|
iter = begin;
|
|
|
|
if (!FindCharInReadable('/', iter, end)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-10-01 17:21:45 -07:00
|
|
|
const nsCSubstring& host = Substring(begin, iter);
|
|
|
|
|
|
|
|
if (IsCanonicalizedIP(host)) {
|
|
|
|
return hash.FromPlaintext(host, mCryptoHash);
|
|
|
|
}
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
nsCStringArray hostComponents;
|
|
|
|
hostComponents.ParseString(PromiseFlatCString(host).get(), ".");
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
if (hostComponents.Count() < 2)
|
2007-07-25 23:38:43 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
PRInt32 last = hostComponents.Count() - 1;
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCAutoString lookupHost;
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
if (hostComponents.Count() > 2) {
|
|
|
|
lookupHost.Append(*hostComponents[last - 2]);
|
2007-07-25 23:38:43 -07:00
|
|
|
lookupHost.Append(".");
|
|
|
|
}
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
lookupHost.Append(*hostComponents[last - 1]);
|
2007-07-25 23:38:43 -07:00
|
|
|
lookupHost.Append(".");
|
2007-11-13 21:31:07 -08:00
|
|
|
lookupHost.Append(*hostComponents[last]);
|
2007-07-25 23:38:43 -07:00
|
|
|
lookupHost.Append("/");
|
|
|
|
|
|
|
|
return hash.FromPlaintext(lookupHost, mCryptoHash);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::GetChunkEntries(const nsACString& table,
|
|
|
|
PRUint32 tableId,
|
|
|
|
PRUint32 chunkNum,
|
|
|
|
nsACString& chunk,
|
|
|
|
nsTArray<nsUrlClassifierEntry>& entries)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
if (StringEndsWith(table, NS_LITERAL_CSTRING("-exp"))) {
|
|
|
|
// regexp tables need to be ungzipped
|
|
|
|
rv = InflateChunk(chunk);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (StringEndsWith(table, NS_LITERAL_CSTRING("-sha128"))) {
|
|
|
|
PRUint32 start = 0;
|
|
|
|
while (start + KEY_LENGTH + 1 <= chunk.Length()) {
|
|
|
|
nsUrlClassifierEntry* entry = entries.AppendElement();
|
|
|
|
if (!entry) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
// first 16 bytes are the domain/key
|
|
|
|
entry->mKey.Assign(Substring(chunk, start, KEY_LENGTH));
|
|
|
|
|
|
|
|
start += KEY_LENGTH;
|
|
|
|
// then there is a one-byte count of fragments
|
|
|
|
PRUint8 numEntries = static_cast<PRUint8>(chunk[start]);
|
|
|
|
start++;
|
|
|
|
|
|
|
|
if (numEntries == 0) {
|
|
|
|
// if there are no fragments, the domain itself is treated as a
|
|
|
|
// fragment
|
|
|
|
entry->AddFragment(entry->mKey, chunkNum);
|
|
|
|
} else {
|
|
|
|
if (start + (numEntries * KEY_LENGTH) >= chunk.Length()) {
|
|
|
|
// there isn't as much data as they said there would be.
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PRUint8 i = 0; i < numEntries; i++) {
|
|
|
|
nsUrlClassifierHash hash;
|
|
|
|
hash.Assign(Substring(chunk, start, KEY_LENGTH));
|
|
|
|
entry->AddFragment(hash, chunkNum);
|
|
|
|
start += KEY_LENGTH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2007-11-13 21:31:07 -08:00
|
|
|
nsCStringArray lines;
|
|
|
|
lines.ParseString(PromiseFlatCString(chunk).get(), "\n");
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
// non-hashed tables need to be hashed
|
|
|
|
for (PRInt32 i = 0; i < lines.Count(); i++) {
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierEntry* entry = entries.AppendElement();
|
|
|
|
if (!entry) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
rv = GetKey(*lines[i], entry->mKey);
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
entry->mTableId = tableId;
|
|
|
|
nsUrlClassifierHash hash;
|
2007-11-13 21:31:07 -08:00
|
|
|
hash.FromPlaintext(*lines[i], mCryptoHash);
|
2007-07-25 23:38:43 -07:00
|
|
|
entry->AddFragment(hash, mChunkNum);
|
2007-11-13 21:31:07 -08:00
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ParseChunkList(const nsACString& chunkStr,
|
|
|
|
nsTArray<PRUint32>& chunks)
|
|
|
|
{
|
|
|
|
LOG(("Parsing %s", PromiseFlatCString(chunkStr).get()));
|
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
nsCStringArray elements;
|
|
|
|
elements.ParseString(PromiseFlatCString(chunkStr).get() , ",");
|
2007-07-25 23:38:43 -07:00
|
|
|
|
2007-11-13 21:31:07 -08:00
|
|
|
for (PRInt32 i = 0; i < elements.Count(); i++) {
|
|
|
|
nsCString& element = *elements[i];
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
PRUint32 first;
|
|
|
|
PRUint32 last;
|
|
|
|
if (PR_sscanf(element.get(), "%u-%u", &first, &last) == 2) {
|
|
|
|
if (first > last) {
|
|
|
|
PRUint32 tmp = first;
|
|
|
|
first = last;
|
|
|
|
last = tmp;
|
|
|
|
}
|
|
|
|
for (PRUint32 num = first; num <= last; num++) {
|
|
|
|
chunks.AppendElement(num);
|
|
|
|
}
|
|
|
|
} else if (PR_sscanf(element.get(), "%u", &first) == 1) {
|
|
|
|
chunks.AppendElement(first);
|
|
|
|
}
|
2007-11-13 21:31:07 -08:00
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
LOG(("Got %d elements.", chunks.Length()));
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::JoinChunkList(nsTArray<PRUint32>& chunks,
|
|
|
|
nsCString& chunkStr)
|
|
|
|
{
|
|
|
|
chunkStr.Truncate();
|
|
|
|
chunks.Sort();
|
|
|
|
|
|
|
|
PRUint32 i = 0;
|
|
|
|
while (i < chunks.Length()) {
|
|
|
|
if (i != 0) {
|
|
|
|
chunkStr.Append(',');
|
|
|
|
}
|
|
|
|
chunkStr.AppendInt(chunks[i]);
|
|
|
|
|
|
|
|
PRUint32 first = i;
|
|
|
|
PRUint32 last = first;
|
|
|
|
i++;
|
|
|
|
while (i < chunks.Length() && chunks[i] == chunks[i - 1] + 1) {
|
|
|
|
last = chunks[i++];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last != first) {
|
|
|
|
chunkStr.Append('-');
|
|
|
|
chunkStr.AppendInt(last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::GetChunkLists(PRUint32 tableId,
|
|
|
|
nsACString& addChunks,
|
|
|
|
nsACString& subChunks)
|
|
|
|
{
|
|
|
|
addChunks.Truncate();
|
|
|
|
subChunks.Truncate();
|
|
|
|
|
|
|
|
mozStorageStatementScoper scoper(mGetChunkListsStatement);
|
|
|
|
|
|
|
|
nsresult rv = mGetChunkListsStatement->BindInt32Parameter(0, tableId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool hasMore = PR_FALSE;
|
|
|
|
rv = mGetChunkListsStatement->ExecuteStep(&hasMore);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (!hasMore) {
|
|
|
|
LOG(("Getting chunks for %d, found nothing", tableId));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = mGetChunkListsStatement->GetUTF8String(0, addChunks);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = mGetChunkListsStatement->GetUTF8String(1, subChunks);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
LOG(("Getting chunks for %d, got %s %s",
|
|
|
|
tableId,
|
|
|
|
PromiseFlatCString(addChunks).get(),
|
|
|
|
PromiseFlatCString(subChunks).get()));
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::SetChunkLists(PRUint32 tableId,
|
|
|
|
const nsACString& addChunks,
|
|
|
|
const nsACString& subChunks)
|
|
|
|
{
|
|
|
|
mozStorageStatementScoper scoper(mSetChunkListsStatement);
|
|
|
|
|
|
|
|
mSetChunkListsStatement->BindUTF8StringParameter(0, addChunks);
|
|
|
|
mSetChunkListsStatement->BindUTF8StringParameter(1, subChunks);
|
|
|
|
mSetChunkListsStatement->BindInt32Parameter(2, tableId);
|
|
|
|
nsresult rv = mSetChunkListsStatement->Execute();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-12-03 20:49:22 -08:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::CacheChunkLists(PRUint32 tableId,
|
|
|
|
PRBool parseAdds,
|
|
|
|
PRBool parseSubs)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (mHaveCachedLists && mCachedListsTable != tableId) {
|
|
|
|
rv = FlushChunkLists();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mHaveCachedLists) {
|
|
|
|
rv = GetChunkLists(tableId, mCachedAddsStr, mCachedSubsStr);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mHaveCachedLists = PR_TRUE;
|
|
|
|
mCachedListsTable = tableId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseAdds && !mHaveCachedAddChunks) {
|
|
|
|
ParseChunkList(mCachedAddsStr, mCachedAddChunks);
|
|
|
|
mHaveCachedAddChunks = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseSubs && !mHaveCachedSubChunks) {
|
|
|
|
ParseChunkList(mCachedSubsStr, mCachedSubChunks);
|
|
|
|
mHaveCachedSubChunks = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::FlushChunkLists()
|
|
|
|
{
|
|
|
|
if (!mHaveCachedLists) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mHaveCachedAddChunks) {
|
|
|
|
JoinChunkList(mCachedAddChunks, mCachedAddsStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mHaveCachedSubChunks) {
|
|
|
|
JoinChunkList(mCachedSubChunks, mCachedSubsStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = SetChunkLists(mCachedListsTable,
|
|
|
|
mCachedAddsStr, mCachedSubsStr);
|
|
|
|
// clear out the cache before checking/returning the error here.
|
|
|
|
|
|
|
|
mCachedAddsStr.Truncate();
|
|
|
|
mCachedSubsStr.Truncate();
|
|
|
|
mCachedListsTable = PR_UINT32_MAX;
|
|
|
|
mHaveCachedLists = PR_FALSE;
|
|
|
|
|
|
|
|
mCachedAddChunks.Clear();
|
|
|
|
mHaveCachedAddChunks = PR_FALSE;
|
|
|
|
|
|
|
|
mCachedSubChunks.Clear();
|
|
|
|
mHaveCachedSubChunks = PR_FALSE;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::AddChunk(PRUint32 tableId,
|
|
|
|
PRUint32 chunkNum,
|
|
|
|
nsTArray<nsUrlClassifierEntry>& entries)
|
|
|
|
{
|
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
PRIntervalTime clockStart = 0;
|
|
|
|
if (LOG_ENABLED()) {
|
|
|
|
clockStart = PR_IntervalNow();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
LOG(("Adding %d entries to chunk %d", entries.Length(), chunkNum));
|
|
|
|
|
2007-12-03 20:49:22 -08:00
|
|
|
nsresult rv = CacheChunkLists(tableId, PR_TRUE, PR_FALSE);
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-12-03 20:49:22 -08:00
|
|
|
mCachedAddChunks.AppendElement(chunkNum);
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
nsTArray<PRUint32> entryIDs;
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < entries.Length(); i++) {
|
|
|
|
nsUrlClassifierEntry& thisEntry = entries[i];
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
nsUrlClassifierEntry existingEntry;
|
|
|
|
rv = ReadEntry(thisEntry.mKey, tableId, existingEntry);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (!existingEntry.Merge(thisEntry))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
rv = WriteEntry(existingEntry);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
entryIDs.AppendElement(existingEntry.mId);
|
|
|
|
}
|
|
|
|
|
|
|
|
mozStorageStatementScoper scoper(mAddChunkEntriesStatement);
|
|
|
|
rv = mAddChunkEntriesStatement->BindInt32Parameter(0, chunkNum);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mAddChunkEntriesStatement->BindInt32Parameter(1, tableId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mAddChunkEntriesStatement->BindBlobParameter
|
|
|
|
(2,
|
|
|
|
reinterpret_cast<PRUint8*>(entryIDs.Elements()),
|
|
|
|
entryIDs.Length() * sizeof(PRUint32));
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
rv = mAddChunkEntriesStatement->Execute();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
if (LOG_ENABLED()) {
|
|
|
|
PRIntervalTime clockEnd = PR_IntervalNow();
|
|
|
|
printf("adding chunk %d took %dms\n", chunkNum,
|
|
|
|
PR_IntervalToMilliseconds(clockEnd - clockStart));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ExpireAdd(PRUint32 tableId,
|
|
|
|
PRUint32 chunkNum)
|
|
|
|
{
|
|
|
|
LOG(("Expiring chunk %d\n", chunkNum));
|
|
|
|
|
2007-12-03 20:49:22 -08:00
|
|
|
nsresult rv = CacheChunkLists(tableId, PR_TRUE, PR_FALSE);
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-12-03 20:49:22 -08:00
|
|
|
mCachedAddChunks.RemoveElement(chunkNum);
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
mozStorageStatementScoper getChunkEntriesScoper(mGetChunkEntriesStatement);
|
|
|
|
|
|
|
|
rv = mGetChunkEntriesStatement->BindInt32Parameter(0, chunkNum);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = mGetChunkEntriesStatement->BindInt32Parameter(1, tableId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
PRBool exists;
|
|
|
|
rv = mGetChunkEntriesStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
while (exists) {
|
|
|
|
PRUint32 size;
|
|
|
|
const PRUint8* blob = mGetChunkEntriesStatement->AsSharedBlob(0, &size);
|
|
|
|
if (blob) {
|
|
|
|
const PRUint32* entries = reinterpret_cast<const PRUint32*>(blob);
|
|
|
|
for (PRUint32 i = 0; i < (size / sizeof(PRUint32)); i++) {
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
nsUrlClassifierEntry entry;
|
|
|
|
rv = ReadEntry(entries[i], entry);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
entry.SubtractChunk(chunkNum);
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
rv = WriteEntry(entry);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
rv = mGetChunkEntriesStatement->ExecuteStep(&exists);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
mozStorageStatementScoper removeScoper(mDeleteChunkEntriesStatement);
|
|
|
|
mDeleteChunkEntriesStatement->BindInt32Parameter(0, tableId);
|
|
|
|
mDeleteChunkEntriesStatement->BindInt32Parameter(1, chunkNum);
|
|
|
|
rv = mDeleteChunkEntriesStatement->Execute();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-12-03 20:35:25 -08:00
|
|
|
return NS_OK;
|
2007-07-25 23:38:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::SubChunk(PRUint32 tableId,
|
|
|
|
PRUint32 chunkNum,
|
|
|
|
nsTArray<nsUrlClassifierEntry>& entries)
|
|
|
|
{
|
2007-12-03 20:49:22 -08:00
|
|
|
nsresult rv = CacheChunkLists(tableId, PR_FALSE, PR_TRUE);
|
|
|
|
mCachedSubChunks.AppendElement(chunkNum);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
for (PRUint32 i = 0; i < entries.Length(); i++) {
|
|
|
|
nsUrlClassifierEntry& thisEntry = entries[i];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
HandlePendingLookups();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierEntry existingEntry;
|
|
|
|
rv = ReadEntry(thisEntry.mKey, tableId, existingEntry);
|
2007-07-25 20:11:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
if (!existingEntry.SubtractFragments(thisEntry))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
|
|
|
rv = WriteEntry(existingEntry);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 20:11:43 -07:00
|
|
|
}
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-12-03 20:35:25 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ExpireSub(PRUint32 tableId, PRUint32 chunkNum)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-12-03 20:49:22 -08:00
|
|
|
nsresult rv = CacheChunkLists(tableId, PR_FALSE, PR_TRUE);
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-12-03 20:49:22 -08:00
|
|
|
mCachedSubChunks.RemoveElement(chunkNum);
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-12-03 20:35:25 -08:00
|
|
|
return NS_OK;
|
2007-07-25 18:49:20 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ProcessChunk(PRBool* done)
|
2007-07-25 18:49:20 -07:00
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
// wait until the chunk plus terminating \n has been read
|
|
|
|
if (mPendingStreamUpdate.Length() <= static_cast<PRUint32>(mChunkLen)) {
|
|
|
|
*done = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-07-25 20:11:43 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
if (mPendingStreamUpdate[mChunkLen] != '\n') {
|
|
|
|
LOG(("Didn't get a terminating newline after the chunk, failing the update"));
|
2007-07-25 20:11:43 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCAutoString chunk;
|
|
|
|
chunk.Assign(Substring(mPendingStreamUpdate, 0, mChunkLen));
|
|
|
|
mPendingStreamUpdate = Substring(mPendingStreamUpdate, mChunkLen);
|
|
|
|
|
|
|
|
LOG(("Handling a chunk sized %d", chunk.Length()));
|
|
|
|
|
|
|
|
nsTArray<nsUrlClassifierEntry> entries;
|
|
|
|
GetChunkEntries(mUpdateTable, mUpdateTableId, mChunkNum, chunk, entries);
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (mChunkType == CHUNK_ADD) {
|
|
|
|
rv = AddChunk(mUpdateTableId, mChunkNum, entries);
|
|
|
|
} else {
|
|
|
|
rv = SubChunk(mUpdateTableId, mChunkNum, entries);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pop off the chunk and the trailing \n
|
|
|
|
mPendingStreamUpdate = Substring(mPendingStreamUpdate, 1);
|
|
|
|
|
|
|
|
mState = STATE_LINE;
|
|
|
|
*done = PR_FALSE;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::ProcessResponseLines(PRBool* done)
|
|
|
|
{
|
2007-07-25 20:11:43 -07:00
|
|
|
PRUint32 cur = 0;
|
|
|
|
PRInt32 next;
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
// We will run to completion unless we find a chunk line
|
|
|
|
*done = PR_TRUE;
|
|
|
|
|
|
|
|
nsACString& updateString = mPendingStreamUpdate;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
while(cur < updateString.Length() &&
|
|
|
|
(next = updateString.FindChar('\n', cur)) != kNotFound) {
|
2007-07-25 23:38:43 -07:00
|
|
|
const nsCSubstring& line = Substring(updateString, cur, next - cur);
|
|
|
|
cur = next + 1;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
LOG(("Processing %s\n", PromiseFlatCString(line).get()));
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
if (StringBeginsWith(line, NS_LITERAL_CSTRING("n:"))) {
|
|
|
|
if (PR_sscanf(PromiseFlatCString(line).get(), "n:%d",
|
|
|
|
&mUpdateWait) != 1) {
|
|
|
|
LOG(("Error parsing n: field: %s", PromiseFlatCString(line).get()));
|
|
|
|
mUpdateWait = 0;
|
|
|
|
}
|
|
|
|
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("k:"))) {
|
|
|
|
// XXX: pleaserekey
|
|
|
|
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("i:"))) {
|
|
|
|
const nsCSubstring& data = Substring(line, 2);
|
|
|
|
PRInt32 comma;
|
|
|
|
if ((comma = data.FindChar(',')) == kNotFound) {
|
|
|
|
mUpdateTable = data;
|
|
|
|
} else {
|
|
|
|
mUpdateTable = Substring(data, 0, comma);
|
|
|
|
// The rest is the mac, which we don't support for now
|
|
|
|
}
|
|
|
|
GetTableId(mUpdateTable, &mUpdateTableId);
|
|
|
|
LOG(("update table: '%s' (%d)", mUpdateTable.get(), mUpdateTableId));
|
|
|
|
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("a:")) ||
|
|
|
|
StringBeginsWith(line, NS_LITERAL_CSTRING("s:"))) {
|
|
|
|
mState = STATE_CHUNK;
|
|
|
|
char command;
|
|
|
|
if (PR_sscanf(PromiseFlatCString(line).get(),
|
|
|
|
"%c:%d:%d", &command, &mChunkNum, &mChunkLen) != 3 ||
|
|
|
|
mChunkLen > MAX_CHUNK_SIZE) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
mChunkType = (command == 'a') ? CHUNK_ADD : CHUNK_SUB;
|
|
|
|
|
|
|
|
// Done parsing lines, move to chunk state now
|
|
|
|
*done = PR_FALSE;
|
|
|
|
break;
|
|
|
|
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("ad:"))) {
|
|
|
|
PRUint32 chunkNum;
|
|
|
|
if (PR_sscanf(PromiseFlatCString(line).get(), "ad:%u", &chunkNum) != 1) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
rv = ExpireAdd(mUpdateTableId, chunkNum);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
} else if (StringBeginsWith(line, NS_LITERAL_CSTRING("sd:"))) {
|
|
|
|
PRUint32 chunkNum;
|
|
|
|
if (PR_sscanf(PromiseFlatCString(line).get(), "ad:%u", &chunkNum) != 1) {
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-07-25 18:49:20 -07:00
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = ExpireSub(mUpdateTableId, chunkNum);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-07-25 23:38:43 -07:00
|
|
|
LOG(("ignoring unknown line: '%s'", PromiseFlatCString(line).get()));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mPendingStreamUpdate = Substring(updateString, cur);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
void
|
|
|
|
nsUrlClassifierDBServiceWorker::ResetUpdate()
|
|
|
|
{
|
|
|
|
mUpdateWait = 0;
|
|
|
|
mState = STATE_LINE;
|
|
|
|
mChunkNum = 0;
|
|
|
|
mChunkLen = 0;
|
|
|
|
mUpdateStatus = NS_OK;
|
|
|
|
|
|
|
|
mUpdateTable.Truncate();
|
|
|
|
mPendingStreamUpdate.Truncate();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updating the database:
|
|
|
|
*
|
|
|
|
* The Update() method takes a series of chunks seperated with control data,
|
|
|
|
* as described in
|
|
|
|
* http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec
|
|
|
|
*
|
|
|
|
* It will iterate through the control data until it reaches a chunk. By
|
|
|
|
* the time it reaches a chunk, it should have received
|
|
|
|
* a) the table to which this chunk applies
|
|
|
|
* b) the type of chunk (add, delete, expire add, expire delete).
|
|
|
|
* c) the chunk ID
|
|
|
|
* d) the length of the chunk.
|
|
|
|
*
|
|
|
|
* For add and subtract chunks, it needs to read the chunk data (expires
|
|
|
|
* don't have any data). Chunk data is a list of URI fragments whose
|
|
|
|
* encoding depends on the type of table (which is indicated by the end
|
|
|
|
* of the table name):
|
|
|
|
* a) tables ending with -exp are a zlib-compressed list of URI fragments
|
|
|
|
* separated by newlines.
|
|
|
|
* b) tables ending with -sha128 have the form
|
|
|
|
* [domain][N][frag0]...[fragN]
|
|
|
|
* 16 1 16 16
|
|
|
|
* If N is 0, the domain is reused as a fragment.
|
|
|
|
* c) any other tables are assumed to be a plaintext list of URI fragments
|
|
|
|
* separated by newlines.
|
|
|
|
*
|
|
|
|
* Update() can be fed partial data; It will accumulate data until there is
|
|
|
|
* enough to act on. Finish() should be called when there will be no more
|
|
|
|
* data.
|
|
|
|
*/
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBServiceWorker::Update(const nsACString& chunk)
|
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
if (gShuttingDownThread)
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
|
|
|
|
HandlePendingLookups();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("Update from Stream."));
|
|
|
|
nsresult rv = OpenDb();
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_ERROR("Unable to open database");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// if something has gone wrong during this update, just throw it away
|
|
|
|
if (NS_FAILED(mUpdateStatus)) {
|
|
|
|
return mUpdateStatus;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-12-03 20:35:25 -08:00
|
|
|
PRBool transaction;
|
|
|
|
if (NS_SUCCEEDED(mConnection->GetTransactionInProgress(&transaction)) &&
|
|
|
|
!transaction) {
|
|
|
|
rv = mConnection->BeginTransaction();
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mUpdateStatus = rv;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
LOG(("Got %s\n", PromiseFlatCString(chunk).get()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mPendingStreamUpdate.Append(chunk);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
PRBool done = PR_FALSE;
|
|
|
|
while (!done) {
|
|
|
|
if (mState == STATE_CHUNK) {
|
|
|
|
rv = ProcessChunk(&done);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = ProcessResponseLines(&done);
|
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mUpdateStatus = rv;
|
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierDBServiceWorker::Finish(nsIUrlClassifierCallback* aSuccessCallback,
|
|
|
|
nsIUrlClassifierCallback* aErrorCallback)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-12-03 20:49:22 -08:00
|
|
|
if (NS_SUCCEEDED(mUpdateStatus)) {
|
|
|
|
mUpdateStatus = FlushChunkLists();
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCAutoString arg;
|
2007-12-03 20:35:25 -08:00
|
|
|
if (NS_SUCCEEDED(mUpdateStatus)) {
|
|
|
|
mUpdateStatus = mConnection->CommitTransaction();
|
|
|
|
} else {
|
|
|
|
mConnection->RollbackTransaction();
|
|
|
|
}
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
if (NS_SUCCEEDED(mUpdateStatus)) {
|
|
|
|
arg.AppendInt(mUpdateWait);
|
|
|
|
aSuccessCallback->HandleEvent(arg);
|
2007-07-25 20:11:43 -07:00
|
|
|
} else {
|
2007-07-25 23:38:43 -07:00
|
|
|
arg.AppendInt(mUpdateStatus);
|
|
|
|
aErrorCallback->HandleEvent(arg);
|
2007-07-25 20:11:43 -07:00
|
|
|
}
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
ResetUpdate();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBServiceWorker::CancelStream()
|
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
LOG(("CancelStream"));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
ResetUpdate();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
if (mConnection) {
|
|
|
|
mLookupStatement = nsnull;
|
|
|
|
mLookupWithTableStatement = nsnull;
|
|
|
|
mLookupWithIDStatement = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mUpdateStatement = nsnull;
|
|
|
|
mDeleteStatement = nsnull;
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mAddChunkEntriesStatement = nsnull;
|
|
|
|
mGetChunkEntriesStatement = nsnull;
|
|
|
|
mDeleteChunkEntriesStatement = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mGetChunkListsStatement = nsnull;
|
|
|
|
mSetChunkListsStatement = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mGetTablesStatement = nsnull;
|
|
|
|
mGetTableIdStatement = nsnull;
|
|
|
|
mGetTableNameStatement = nsnull;
|
|
|
|
mInsertTableIdStatement = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mConnection = nsnull;
|
|
|
|
LOG(("urlclassifier db closed\n"));
|
2007-07-25 20:11:43 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mCryptoHash = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
return NS_OK;
|
2007-07-25 20:11:43 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 20:11:43 -07:00
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBServiceWorker::OpenDb()
|
|
|
|
{
|
|
|
|
// Connection already open, don't do anything.
|
2007-07-25 23:38:43 -07:00
|
|
|
if (mConnection)
|
2007-07-25 20:11:43 -07:00
|
|
|
return NS_OK;
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 20:11:43 -07:00
|
|
|
LOG(("Opening db\n"));
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult rv;
|
2007-07-25 20:11:43 -07:00
|
|
|
// open the connection
|
|
|
|
nsCOMPtr<mozIStorageService> storageService =
|
|
|
|
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
2007-07-25 18:49:20 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 23:38:43 -07:00
|
|
|
|
|
|
|
nsCOMPtr<mozIStorageConnection> connection;
|
|
|
|
rv = storageService->OpenDatabase(mDBFile, getter_AddRefs(connection));
|
2007-07-25 20:11:43 -07:00
|
|
|
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
|
|
|
// delete the db and try opening again
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = mDBFile->Remove(PR_FALSE);
|
2007-07-25 20:11:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = storageService->OpenDatabase(mDBFile, getter_AddRefs(connection));
|
2007-07-25 20:11:43 -07:00
|
|
|
}
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous=OFF"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA page_size=4096"));
|
2007-07-25 18:49:20 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA default_page_size=4096"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 18:49:20 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Create the table
|
|
|
|
rv = MaybeCreateTables(connection);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 20:11:43 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT * FROM moz_classifier"
|
|
|
|
" WHERE domain=?1"),
|
|
|
|
getter_AddRefs(mLookupStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT * FROM moz_classifier"
|
|
|
|
" WHERE domain=?1 AND table_id=?2"),
|
|
|
|
getter_AddRefs(mLookupWithTableStatement));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT * FROM moz_classifier"
|
|
|
|
" WHERE id=?1"),
|
|
|
|
getter_AddRefs(mLookupWithIDStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("INSERT OR REPLACE INTO moz_classifier"
|
|
|
|
" VALUES (?1, ?2, ?3, ?4)"),
|
|
|
|
getter_AddRefs(mUpdateStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("DELETE FROM moz_classifier"
|
|
|
|
" WHERE id=?1"),
|
|
|
|
getter_AddRefs(mDeleteStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("INSERT OR REPLACE INTO moz_chunks VALUES (?1, ?2, ?3)"),
|
|
|
|
getter_AddRefs(mAddChunkEntriesStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT entries FROM moz_chunks"
|
|
|
|
" WHERE chunk_id = ?1 AND table_id = ?2"),
|
|
|
|
getter_AddRefs(mGetChunkEntriesStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("DELETE FROM moz_chunks WHERE table_id=?1 AND chunk_id=?2"),
|
|
|
|
getter_AddRefs(mDeleteChunkEntriesStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT add_chunks, sub_chunks FROM moz_tables"
|
|
|
|
" WHERE id=?1"),
|
|
|
|
getter_AddRefs(mGetChunkListsStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("UPDATE moz_tables"
|
|
|
|
" SET add_chunks=?1, sub_chunks=?2"
|
|
|
|
" WHERE id=?3"),
|
|
|
|
getter_AddRefs(mSetChunkListsStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT name, add_chunks, sub_chunks"
|
|
|
|
" FROM moz_tables"),
|
|
|
|
getter_AddRefs(mGetTablesStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 20:11:43 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT id FROM moz_tables"
|
|
|
|
" WHERE name = ?1"),
|
|
|
|
getter_AddRefs(mGetTableIdStatement));
|
2007-07-25 18:49:20 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("SELECT name FROM moz_tables"
|
|
|
|
" WHERE id = ?1"),
|
|
|
|
getter_AddRefs(mGetTableNameStatement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-07-25 20:11:43 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->CreateStatement
|
|
|
|
(NS_LITERAL_CSTRING("INSERT INTO moz_tables(id, name, add_chunks, sub_chunks)"
|
|
|
|
" VALUES (null, ?1, null, null)"),
|
|
|
|
getter_AddRefs(mInsertTableIdStatement));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
mConnection = connection;
|
|
|
|
|
|
|
|
mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierDBServiceWorker::MaybeCreateTables(mozIStorageConnection* connection)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
LOG(("MaybeCreateTables\n"));
|
|
|
|
|
|
|
|
nsresult rv = connection->ExecuteSimpleSQL(
|
|
|
|
NS_LITERAL_CSTRING("CREATE TABLE IF NOT EXISTS moz_classifier"
|
|
|
|
" (id INTEGER PRIMARY KEY,"
|
|
|
|
" domain BLOB,"
|
|
|
|
" data BLOB,"
|
|
|
|
" table_id INTEGER)"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(
|
|
|
|
NS_LITERAL_CSTRING("CREATE UNIQUE INDEX IF NOT EXISTS"
|
|
|
|
" moz_classifier_domain_index"
|
|
|
|
" ON moz_classifier(domain, table_id)"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(
|
|
|
|
NS_LITERAL_CSTRING("CREATE TABLE IF NOT EXISTS moz_tables"
|
|
|
|
" (id INTEGER PRIMARY KEY,"
|
|
|
|
" name TEXT,"
|
|
|
|
" add_chunks TEXT,"
|
|
|
|
" sub_chunks TEXT);"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(
|
|
|
|
NS_LITERAL_CSTRING("CREATE TABLE IF NOT EXISTS moz_chunks"
|
|
|
|
" (chunk_id INTEGER,"
|
|
|
|
" table_id INTEGER,"
|
|
|
|
" entries BLOB)"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = connection->ExecuteSimpleSQL(
|
|
|
|
NS_LITERAL_CSTRING("CREATE INDEX IF NOT EXISTS moz_chunks_id"
|
|
|
|
" ON moz_chunks(chunk_id)"));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Helper class for nsIURIClassifier implementation, translates table names
|
|
|
|
// to nsIURIClassifier enums.
|
|
|
|
|
|
|
|
class nsUrlClassifierClassifyCallback : public nsIUrlClassifierCallback
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIURLCLASSIFIERCALLBACK
|
|
|
|
|
2007-12-03 21:10:22 -08:00
|
|
|
nsUrlClassifierClassifyCallback(nsIURIClassifierCallback *c,
|
|
|
|
PRBool checkMalware,
|
|
|
|
PRBool checkPhishing)
|
2007-08-31 16:18:46 -07:00
|
|
|
: mCallback(c)
|
2007-12-03 21:10:22 -08:00
|
|
|
, mCheckMalware(checkMalware)
|
|
|
|
, mCheckPhishing(checkPhishing)
|
2007-08-31 16:18:46 -07:00
|
|
|
{}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIURIClassifierCallback> mCallback;
|
2007-12-03 21:10:22 -08:00
|
|
|
PRPackedBool mCheckMalware;
|
|
|
|
PRPackedBool mCheckPhishing;
|
2007-08-31 16:18:46 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierClassifyCallback,
|
2007-08-31 16:48:39 -07:00
|
|
|
nsIUrlClassifierCallback)
|
2007-08-31 16:18:46 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierClassifyCallback::HandleEvent(const nsACString& tables)
|
|
|
|
{
|
|
|
|
// XXX: we should probably have the wardens tell the service which table
|
|
|
|
// names match with which classification. For now the table names give
|
|
|
|
// enough information.
|
|
|
|
nsresult response = NS_OK;
|
|
|
|
|
|
|
|
nsACString::const_iterator begin, end;
|
|
|
|
|
|
|
|
tables.BeginReading(begin);
|
|
|
|
tables.EndReading(end);
|
2007-12-03 21:10:22 -08:00
|
|
|
if (mCheckMalware &&
|
|
|
|
FindInReadable(NS_LITERAL_CSTRING("-malware-"), begin, end)) {
|
2007-08-31 16:18:46 -07:00
|
|
|
response = NS_ERROR_MALWARE_URI;
|
2007-10-29 11:29:14 -07:00
|
|
|
} else {
|
|
|
|
// Reset begin before checking phishing table
|
|
|
|
tables.BeginReading(begin);
|
2007-12-03 21:10:22 -08:00
|
|
|
|
|
|
|
if (mCheckPhishing &&
|
|
|
|
FindInReadable(NS_LITERAL_CSTRING("-phish-"), begin, end)) {
|
2007-10-29 11:29:14 -07:00
|
|
|
response = NS_ERROR_PHISHING_URI;
|
|
|
|
}
|
2007-08-31 16:18:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mCallback->OnClassifyComplete(response);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Proxy class implementation
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS3(nsUrlClassifierDBService,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIUrlClassifierDBService,
|
2007-08-31 16:18:46 -07:00
|
|
|
nsIURIClassifier,
|
2007-03-22 10:30:00 -07:00
|
|
|
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()
|
2007-08-31 16:18:46 -07:00
|
|
|
: mCheckMalware(CHECK_MALWARE_DEFAULT)
|
2007-12-03 21:10:22 -08:00
|
|
|
, mCheckPhishing(CHECK_PHISHING_DEFAULT)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsUrlClassifierDBService::~nsUrlClassifierDBService()
|
|
|
|
{
|
|
|
|
sUrlClassifierDBService = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBService::Init()
|
|
|
|
{
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ASSERTION(sizeof(nsUrlClassifierHash) == KEY_LENGTH,
|
|
|
|
"nsUrlClassifierHash must be KEY_LENGTH bytes long!");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
if (!gUrlClassifierDbServiceLog)
|
|
|
|
gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Force the storage service to be created on the main thread.
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<mozIStorageService> storageService =
|
|
|
|
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-08-09 15:33:04 -07:00
|
|
|
// Force PSM to be loaded on the main thread.
|
|
|
|
nsCOMPtr<nsICryptoHash> hash =
|
|
|
|
do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
// Should we check document loads for malware URIs?
|
|
|
|
nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
|
|
|
|
|
|
if (prefs) {
|
|
|
|
PRBool tmpbool;
|
|
|
|
rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool);
|
|
|
|
mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT;
|
|
|
|
|
|
|
|
prefs->AddObserver(CHECK_MALWARE_PREF, this, PR_FALSE);
|
2007-12-03 21:10:22 -08:00
|
|
|
|
|
|
|
rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool);
|
|
|
|
mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT;
|
|
|
|
|
|
|
|
prefs->AddObserver(CHECK_PHISHING_PREF, this, PR_FALSE);
|
2007-08-31 16:18:46 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Start the background thread.
|
|
|
|
rv = NS_NewThread(&gDbBackgroundThread);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
mWorker = new nsUrlClassifierDBServiceWorker();
|
|
|
|
if (!mWorker)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
rv = mWorker->Init();
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mWorker = nsnull;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Add an observer for shutdown
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
|
|
do_GetService("@mozilla.org/observer-service;1");
|
|
|
|
if (!observerService)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-07-11 09:52:12 -07:00
|
|
|
observerService->AddObserver(this, "profile-before-change", PR_FALSE);
|
|
|
|
observerService->AddObserver(this, "xpcom-shutdown-threads", PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBService::Classify(nsIURI *uri,
|
|
|
|
nsIURIClassifierCallback* c,
|
|
|
|
PRBool* result)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
2007-12-03 21:10:22 -08:00
|
|
|
if (!(mCheckMalware || mCheckPhishing)) {
|
2007-08-31 16:18:46 -07:00
|
|
|
*result = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<nsUrlClassifierClassifyCallback> callback =
|
2007-12-03 21:10:22 -08:00
|
|
|
new nsUrlClassifierClassifyCallback(c, mCheckMalware, mCheckPhishing);
|
2007-08-31 16:18:46 -07:00
|
|
|
if (!callback) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2007-11-27 12:08:02 -08:00
|
|
|
nsresult rv = LookupURI(uri, callback, PR_TRUE);
|
|
|
|
if (rv == NS_ERROR_MALFORMED_URI) {
|
|
|
|
// The URI had no hostname, don't try to classify it.
|
|
|
|
*result = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
*result = PR_TRUE;
|
2007-11-27 12:08:02 -08:00
|
|
|
return NS_OK;
|
2007-08-31 16:18:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierDBService::Lookup(const nsACString& spec,
|
|
|
|
nsIUrlClassifierCallback* c,
|
|
|
|
PRBool needsProxy)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), spec);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
uri = NS_GetInnermostURI(uri);
|
|
|
|
if (!uri) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
return LookupURI(uri, c, needsProxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBService::LookupURI(nsIURI* uri,
|
|
|
|
nsIUrlClassifierCallback* c,
|
|
|
|
PRBool needsProxy)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCAutoString key;
|
|
|
|
// Canonicalize the url
|
|
|
|
nsCOMPtr<nsIUrlClassifierUtils> utilsService =
|
|
|
|
do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
|
2007-08-31 16:18:46 -07:00
|
|
|
nsresult rv = utilsService->GetKeyForURI(uri, key);
|
2007-07-25 23:38:43 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIUrlClassifierCallback> proxyCallback;
|
2007-07-25 23:38:43 -07:00
|
|
|
if (needsProxy) {
|
|
|
|
// The proxy callback uses the current thread.
|
|
|
|
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
|
|
|
NS_GET_IID(nsIUrlClassifierCallback),
|
|
|
|
c,
|
|
|
|
NS_PROXY_ASYNC,
|
|
|
|
getter_AddRefs(proxyCallback));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
} else {
|
|
|
|
proxyCallback = c;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
// Queue this lookup and call the lookup function to flush the queue if
|
|
|
|
// necessary.
|
|
|
|
rv = mWorker->QueueLookup(key, proxyCallback);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return proxy->Lookup(EmptyCString(), nsnull, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierDBService::GetTables(nsIUrlClassifierCallback* c)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
return proxy->GetTables(proxyCallback);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBService::Update(const nsACString& aUpdateChunk)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
|
|
|
nsresult 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->Update(aUpdateChunk);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-07-25 23:38:43 -07:00
|
|
|
nsUrlClassifierDBService::Finish(nsIUrlClassifierCallback* aSuccessCallback,
|
|
|
|
nsIUrlClassifierCallback* aErrorCallback)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
// The proxy callback uses the current thread.
|
2007-07-25 23:38:43 -07:00
|
|
|
nsCOMPtr<nsIUrlClassifierCallback> proxySuccessCallback;
|
|
|
|
if (aSuccessCallback) {
|
|
|
|
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
|
|
|
NS_GET_IID(nsIUrlClassifierCallback),
|
|
|
|
aSuccessCallback,
|
|
|
|
NS_PROXY_ASYNC,
|
|
|
|
getter_AddRefs(proxySuccessCallback));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIUrlClassifierCallback> proxyErrorCallback;
|
|
|
|
if (aErrorCallback) {
|
|
|
|
rv = NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
|
|
|
NS_GET_IID(nsIUrlClassifierCallback),
|
|
|
|
aErrorCallback,
|
|
|
|
NS_PROXY_ASYNC,
|
|
|
|
getter_AddRefs(proxyErrorCallback));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2007-07-25 23:38:43 -07:00
|
|
|
return proxy->Finish(proxySuccessCallback, proxyErrorCallback);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBService::CancelStream()
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
|
|
|
nsresult 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->CancelStream();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic,
|
|
|
|
const PRUnichar *aData)
|
|
|
|
{
|
2007-08-31 16:18:46 -07:00
|
|
|
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject, &rv));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) {
|
|
|
|
PRBool tmpbool;
|
|
|
|
rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool);
|
|
|
|
mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT;
|
2007-12-03 21:10:22 -08:00
|
|
|
} else if (NS_LITERAL_STRING(CHECK_PHISHING_PREF).Equals(aData)) {
|
|
|
|
PRBool tmpbool;
|
|
|
|
rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool);
|
|
|
|
mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT;
|
2007-08-31 16:18:46 -07:00
|
|
|
}
|
|
|
|
} else if (!strcmp(aTopic, "profile-before-change") ||
|
|
|
|
!strcmp(aTopic, "xpcom-shutdown-threads")) {
|
|
|
|
Shutdown();
|
|
|
|
} else {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2007-07-11 09:52:12 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Join the background thread if it exists.
|
|
|
|
nsresult
|
|
|
|
nsUrlClassifierDBService::Shutdown()
|
|
|
|
{
|
2007-07-11 09:52:12 -07:00
|
|
|
LOG(("shutting down db service\n"));
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!gDbBackgroundThread)
|
|
|
|
return NS_OK;
|
|
|
|
|
2007-08-31 16:18:46 -07:00
|
|
|
nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
|
|
if (prefs) {
|
|
|
|
prefs->RemoveObserver(CHECK_MALWARE_PREF, this);
|
2007-12-03 21:10:22 -08:00
|
|
|
prefs->RemoveObserver(CHECK_PHISHING_PREF, this);
|
2007-08-31 16:18:46 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv;
|
|
|
|
// First close the db connection.
|
|
|
|
if (mWorker) {
|
|
|
|
nsCOMPtr<nsIUrlClassifierDBServiceWorker> proxy;
|
|
|
|
rv = NS_GetProxyForObject(gDbBackgroundThread,
|
|
|
|
NS_GET_IID(nsIUrlClassifierDBServiceWorker),
|
|
|
|
mWorker,
|
|
|
|
NS_PROXY_ASYNC,
|
|
|
|
getter_AddRefs(proxy));
|
2007-04-24 10:41:44 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = proxy->CloseDb();
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to post close db event");
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
LOG(("joining background thread"));
|
|
|
|
|
2007-04-24 10:41:44 -07:00
|
|
|
gShuttingDownThread = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
gDbBackgroundThread->Shutdown();
|
|
|
|
NS_RELEASE(gDbBackgroundThread);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|