| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "chrome/browser/predictors/logged_in_predictor_table.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <utility> | 
 | #include "base/logging.h" | 
 | #include "base/metrics/histogram.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 
 | #include "sql/statement.h" | 
 |  | 
 | using content::BrowserThread; | 
 | using sql::Statement; | 
 | using std::string; | 
 |  | 
 | namespace { | 
 |  | 
 | const char kTableName[] = "logged_in_predictor"; | 
 |  | 
 | }  // namespace | 
 |  | 
 | namespace predictors { | 
 |  | 
 | LoggedInPredictorTable::LoggedInPredictorTable() | 
 |     : PredictorTableBase() { | 
 | } | 
 |  | 
 | LoggedInPredictorTable::~LoggedInPredictorTable() { | 
 | } | 
 |  | 
 | // static | 
 | string LoggedInPredictorTable::GetKey(const GURL& url) { | 
 |   return GetKeyFromDomain(url.host()); | 
 | } | 
 |  | 
 | // static | 
 | string LoggedInPredictorTable::GetKeyFromDomain(const std::string& domain) { | 
 |   string effective_domain( | 
 |       net::registry_controlled_domains::GetDomainAndRegistry( | 
 |           domain, | 
 |           net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)); | 
 |   if (effective_domain.empty()) | 
 |     effective_domain = domain; | 
 |  | 
 |   // Strip off a preceding ".", if present. | 
 |   if (!effective_domain.empty() && effective_domain[0] == '.') | 
 |     return effective_domain.substr(1); | 
 |   return effective_domain; | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::AddDomainFromURL(const GURL& url) { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, | 
 |       base::StringPrintf("INSERT OR IGNORE INTO %s (domain, time) VALUES (?,?)", | 
 |                          kTableName).c_str())); | 
 |  | 
 |   statement.BindString(0, GetKey(url)); | 
 |   statement.BindInt64(1, base::Time::Now().ToInternalValue()); | 
 |  | 
 |   statement.Run(); | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::DeleteDomainFromURL(const GURL& url) { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, | 
 |       base::StringPrintf("DELETE FROM %s WHERE domain=?", kTableName).c_str())); | 
 |  | 
 |   statement.BindString(0, GetKey(url)); | 
 |  | 
 |   statement.Run(); | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::DeleteDomain(const std::string& domain) { | 
 |   DeleteDomainFromURL(GURL("http://" + domain)); | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::HasUserLoggedIn(const GURL& url, bool* is_present, | 
 |                                              bool* lookup_succeeded) { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   *lookup_succeeded = false; | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, | 
 |       base::StringPrintf("SELECT count(*) FROM %s WHERE domain=?", | 
 |                          kTableName).c_str())); | 
 |  | 
 |   statement.BindString(0, GetKey(url)); | 
 |  | 
 |   if (statement.Step()) { | 
 |     *is_present = (statement.ColumnInt(0) > 0); | 
 |     *lookup_succeeded = true; | 
 |   } | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::DeleteAllCreatedBetween( | 
 |     const base::Time& delete_begin, const base::Time& delete_end) { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, | 
 |       base::StringPrintf("DELETE FROM %s WHERE time >= ? AND time <= ?", | 
 |                          kTableName).c_str())); | 
 |  | 
 |   statement.BindInt64(0, delete_begin.ToInternalValue()); | 
 |   statement.BindInt64(1, delete_end.ToInternalValue()); | 
 |  | 
 |   statement.Run(); | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::GetAllData( | 
 |     LoggedInPredictorTable::LoggedInStateMap* state_map) { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   DCHECK(state_map != NULL); | 
 |   state_map->clear(); | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   Statement statement(DB()->GetUniqueStatement( | 
 |       base::StringPrintf("SELECT * FROM %s", kTableName).c_str())); | 
 |  | 
 |   while (statement.Step()) { | 
 |     string domain = statement.ColumnString(0); | 
 |     int64 value = statement.ColumnInt64(1); | 
 |     (*state_map)[domain] = value; | 
 |   } | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::CreateTableIfNonExistent() { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   sql::Connection* db = DB(); | 
 |   if (db->DoesTableExist(kTableName)) | 
 |     return; | 
 |  | 
 |   const char* table_creator = | 
 |       "CREATE TABLE %s (domain TEXT, time INTEGER, PRIMARY KEY(domain))"; | 
 |  | 
 |   if (!db->Execute(base::StringPrintf(table_creator, kTableName).c_str())) | 
 |     ResetDB(); | 
 | } | 
 |  | 
 | void LoggedInPredictorTable::LogDatabaseStats()  { | 
 |   CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 
 |   if (CantAccessDatabase()) | 
 |     return; | 
 |  | 
 |   Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, | 
 |       base::StringPrintf("SELECT count(*) FROM %s", kTableName).c_str())); | 
 |   if (statement.Step()) | 
 |     UMA_HISTOGRAM_COUNTS("LoggedInPredictor.TableRowCount", | 
 |                          statement.ColumnInt(0)); | 
 | } | 
 |  | 
 | }  // namespace predictors |