1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/predictors/logged_in_predictor_table.h"
6
7#include <algorithm>
8#include <utility>
9#include "base/logging.h"
10#include "base/metrics/histogram.h"
11#include "base/strings/stringprintf.h"
12#include "content/public/browser/browser_thread.h"
13#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
14#include "sql/statement.h"
15
16using content::BrowserThread;
17using sql::Statement;
18using std::string;
19
20namespace {
21
22const char kTableName[] = "logged_in_predictor";
23
24}  // namespace
25
26namespace predictors {
27
28LoggedInPredictorTable::LoggedInPredictorTable()
29    : PredictorTableBase() {
30}
31
32LoggedInPredictorTable::~LoggedInPredictorTable() {
33}
34
35// static
36string LoggedInPredictorTable::GetKey(const GURL& url) {
37  return GetKeyFromDomain(url.host());
38}
39
40// static
41string LoggedInPredictorTable::GetKeyFromDomain(const std::string& domain) {
42  string effective_domain(
43      net::registry_controlled_domains::GetDomainAndRegistry(
44          domain,
45          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
46  if (effective_domain.empty())
47    effective_domain = domain;
48
49  // Strip off a preceding ".", if present.
50  if (!effective_domain.empty() && effective_domain[0] == '.')
51    return effective_domain.substr(1);
52  return effective_domain;
53}
54
55void LoggedInPredictorTable::AddDomainFromURL(const GURL& url) {
56  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
57  if (CantAccessDatabase())
58    return;
59
60  Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
61      base::StringPrintf("INSERT OR IGNORE INTO %s (domain, time) VALUES (?,?)",
62                         kTableName).c_str()));
63
64  statement.BindString(0, GetKey(url));
65  statement.BindInt64(1, base::Time::Now().ToInternalValue());
66
67  statement.Run();
68}
69
70void LoggedInPredictorTable::DeleteDomainFromURL(const GURL& url) {
71  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
72  if (CantAccessDatabase())
73    return;
74
75  Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
76      base::StringPrintf("DELETE FROM %s WHERE domain=?", kTableName).c_str()));
77
78  statement.BindString(0, GetKey(url));
79
80  statement.Run();
81}
82
83void LoggedInPredictorTable::DeleteDomain(const std::string& domain) {
84  DeleteDomainFromURL(GURL("http://" + domain));
85}
86
87void LoggedInPredictorTable::HasUserLoggedIn(const GURL& url, bool* is_present,
88                                             bool* lookup_succeeded) {
89  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
90  *lookup_succeeded = false;
91  if (CantAccessDatabase())
92    return;
93
94  Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
95      base::StringPrintf("SELECT count(*) FROM %s WHERE domain=?",
96                         kTableName).c_str()));
97
98  statement.BindString(0, GetKey(url));
99
100  if (statement.Step()) {
101    *is_present = (statement.ColumnInt(0) > 0);
102    *lookup_succeeded = true;
103  }
104}
105
106void LoggedInPredictorTable::DeleteAllCreatedBetween(
107    const base::Time& delete_begin, const base::Time& delete_end) {
108  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
109  if (CantAccessDatabase())
110    return;
111
112  Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
113      base::StringPrintf("DELETE FROM %s WHERE time >= ? AND time <= ?",
114                         kTableName).c_str()));
115
116  statement.BindInt64(0, delete_begin.ToInternalValue());
117  statement.BindInt64(1, delete_end.ToInternalValue());
118
119  statement.Run();
120}
121
122void LoggedInPredictorTable::GetAllData(
123    LoggedInPredictorTable::LoggedInStateMap* state_map) {
124  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
125  DCHECK(state_map != NULL);
126  state_map->clear();
127  if (CantAccessDatabase())
128    return;
129
130  Statement statement(DB()->GetUniqueStatement(
131      base::StringPrintf("SELECT * FROM %s", kTableName).c_str()));
132
133  while (statement.Step()) {
134    string domain = statement.ColumnString(0);
135    int64 value = statement.ColumnInt64(1);
136    (*state_map)[domain] = value;
137  }
138}
139
140void LoggedInPredictorTable::CreateTableIfNonExistent() {
141  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
142  if (CantAccessDatabase())
143    return;
144
145  sql::Connection* db = DB();
146  if (db->DoesTableExist(kTableName))
147    return;
148
149  const char* table_creator =
150      "CREATE TABLE %s (domain TEXT, time INTEGER, PRIMARY KEY(domain))";
151
152  if (!db->Execute(base::StringPrintf(table_creator, kTableName).c_str()))
153    ResetDB();
154}
155
156void LoggedInPredictorTable::LogDatabaseStats()  {
157  CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
158  if (CantAccessDatabase())
159    return;
160
161  Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
162      base::StringPrintf("SELECT count(*) FROM %s", kTableName).c_str()));
163  if (statement.Step())
164    UMA_HISTOGRAM_COUNTS("LoggedInPredictor.TableRowCount",
165                         statement.ColumnInt(0));
166}
167
168}  // namespace predictors
169