| Index: chrome/browser/extensions/activity_log/ad_network_database.cc
|
| diff --git a/chrome/browser/extensions/activity_log/ad_network_database.cc b/chrome/browser/extensions/activity_log/ad_network_database.cc
|
| index 4b4b45b5aa49730056bf5a8a534eb072a646a133..3ca6700e1e6c2c57dade37d20e85822d6948a4be 100644
|
| --- a/chrome/browser/extensions/activity_log/ad_network_database.cc
|
| +++ b/chrome/browser/extensions/activity_log/ad_network_database.cc
|
| @@ -4,21 +4,113 @@
|
|
|
| #include "chrome/browser/extensions/activity_log/ad_network_database.h"
|
|
|
| +#include "base/basictypes.h"
|
| #include "base/lazy_instance.h"
|
| +#include "base/memory/ref_counted_memory.h"
|
| +#include "crypto/secure_hash.h"
|
| +#include "crypto/sha2.h"
|
| +#include "grit/browser_resources.h"
|
| +#include "ui/base/resource/resource_bundle.h"
|
| +#include "url/gurl.h"
|
|
|
| namespace extensions {
|
|
|
| namespace {
|
|
|
| +// We use a hash size of 8 for these for three reasons.
|
| +// 1. It saves us a bit on space, and, since we have to store these in memory
|
| +// (reading from disk would be far too slow because these checks are
|
| +// performed synchronously), that space is important.
|
| +// 2. Since we don't store full hashes, reconstructing the list is more
|
| +// difficult. This may mean we get a few incorrect hits, but the security is
|
| +// worth the (very small) amount of noise.
|
| +// 3. It fits nicely into a int64.
|
| +const size_t kUrlHashSize = 8u;
|
| +COMPILE_ASSERT(kUrlHashSize <= sizeof(int64), url_hashes_must_fit_into_a_int64);
|
| +
|
| +const size_t kChecksumHashSize = 32u;
|
| +
|
| +class AdNetworkDatabaseImpl : public AdNetworkDatabase {
|
| + public:
|
| + AdNetworkDatabaseImpl();
|
| + virtual ~AdNetworkDatabaseImpl();
|
| +
|
| + private:
|
| + virtual bool IsAdNetwork(const GURL& url) const OVERRIDE;
|
| +
|
| + // Initialize the AdNetworkDatabase. This means initializing the set of
|
| + // hashes from the shared memory.
|
| + void Init();
|
| +
|
| + // The set of partial hashes for known ad networks.
|
| + base::hash_set<int64> entries_;
|
| +};
|
| +
|
| +AdNetworkDatabaseImpl::AdNetworkDatabaseImpl() {
|
| + Init();
|
| +}
|
| +
|
| +AdNetworkDatabaseImpl::~AdNetworkDatabaseImpl() {}
|
| +
|
| +void AdNetworkDatabaseImpl::Init() {
|
| + base::RefCountedStaticMemory* entries_memory =
|
| + ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
|
| + IDR_AD_NETWORK_HASHES);
|
| +
|
| + // This can legitimately happen in unit tests.
|
| + if (!entries_memory)
|
| + return;
|
| +
|
| + const size_t size = entries_memory->size();
|
| + const unsigned char* const front = entries_memory->front();
|
| + if (size < kChecksumHashSize ||
|
| + (size - kChecksumHashSize) % kUrlHashSize != 0) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + // The format of the data resource is fairly straight-forward:
|
| + // <32-bit checksum><list of 64-bit hashes of hosts>, with no linebreaks or
|
| + // other separations.
|
| + scoped_ptr<crypto::SecureHash> hash(
|
| + crypto::SecureHash::Create(crypto::SecureHash::SHA256));
|
| +
|
| + hash->Update(front + kChecksumHashSize, size - kChecksumHashSize);
|
| + char hash_value[kChecksumHashSize];
|
| + hash->Finish(hash_value, kChecksumHashSize);
|
| + // If the checksum doesn't match, abort.
|
| + if (memcmp(hash_value, front, kChecksumHashSize) != 0) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + // Construct and insert all hashes.
|
| + for (const unsigned char* index = front + kChecksumHashSize;
|
| + index < front + size;
|
| + index += kUrlHashSize) {
|
| + int64 value = 0;
|
| + memcpy(&value, index, kUrlHashSize);
|
| + entries_.insert(value);
|
| + }
|
| +}
|
| +
|
| +bool AdNetworkDatabaseImpl::IsAdNetwork(const GURL& url) const {
|
| + int64 hash = 0;
|
| + crypto::SHA256HashString(url.host(), &hash, sizeof(hash));
|
| + // If initialization failed (most likely because this is a unittest), then
|
| + // |entries_| is never populated and we are guaranteed to return false - which
|
| + // is desired default behavior.
|
| + return entries_.count(hash) != 0;
|
| +}
|
| +
|
| class AdNetworkDatabaseFactory {
|
| public:
|
| AdNetworkDatabaseFactory();
|
| ~AdNetworkDatabaseFactory();
|
|
|
| + const AdNetworkDatabase* GetDatabase();
|
| void SetDatabase(scoped_ptr<AdNetworkDatabase> database);
|
|
|
| - const AdNetworkDatabase* database() const { return database_.get(); }
|
| -
|
| private:
|
| scoped_ptr<AdNetworkDatabase> database_;
|
| };
|
| @@ -26,6 +118,14 @@ class AdNetworkDatabaseFactory {
|
| AdNetworkDatabaseFactory::AdNetworkDatabaseFactory() {}
|
| AdNetworkDatabaseFactory::~AdNetworkDatabaseFactory() {}
|
|
|
| +const AdNetworkDatabase* AdNetworkDatabaseFactory::GetDatabase() {
|
| + // Construct a new database, if we don't have one.
|
| + if (!database_.get())
|
| + database_.reset(new AdNetworkDatabaseImpl());
|
| +
|
| + return database_.get();
|
| +}
|
| +
|
| void AdNetworkDatabaseFactory::SetDatabase(
|
| scoped_ptr<AdNetworkDatabase> database) {
|
| database_.reset(database.release());
|
| @@ -40,7 +140,7 @@ AdNetworkDatabase::~AdNetworkDatabase() {}
|
|
|
| // static
|
| const AdNetworkDatabase* AdNetworkDatabase::Get() {
|
| - return g_factory.Get().database();
|
| + return g_factory.Get().GetDatabase();
|
| }
|
|
|
| // static
|
|
|