Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_site_list.cc
blob1bbba47cc70a9520c3983d7754fe3c26a3814c3c
1 // Copyright 2014 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.
5 #include "chrome/browser/supervised_user/supervised_user_site_list.h"
7 #include "base/json/json_file_value_serializer.h"
8 #include "base/logging.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "extensions/common/extension.h"
13 const int kSitelistFormatVersion = 1;
15 const char kCategoriesKey[] = "categories";
16 const char kHostnameHashesKey[] = "hostname_hashes";
17 const char kNameKey[] = "name";
18 const char kSitesKey[] = "sites";
19 const char kSitelistFormatVersionKey[] = "version";
20 const char kThumbnailKey[] = "thumbnail";
21 const char kThumbnailUrlKey[] = "thumbnail_url";
22 const char kUrlKey[] = "url";
23 const char kWhitelistKey[] = "whitelist";
25 namespace {
27 struct CategoryInfo {
28 const char* identifier;
29 const char* name;
32 // These are placeholders for now.
33 CategoryInfo g_categories[] = {
34 {"com.google.chrome.animals", "Animals and Plants"},
35 {"com.google.chrome.arts", "Arts"},
36 {"com.google.chrome.business", "Business"},
37 {"com.google.chrome.computers", "Computers"},
38 {"com.google.chrome.education", "Education"},
39 {"com.google.chrome.entertainment", "Entertainment"},
40 {"com.google.chrome.games", "Games"},
41 {"com.google.chrome.health", "Health"},
42 {"com.google.chrome.home", "Home"},
43 {"com.google.chrome.international", "International"},
44 {"com.google.chrome.news", "News"},
45 {"com.google.chrome.people", "People and Society"},
46 {"com.google.chrome.places", "Places"},
47 {"com.google.chrome.pre-school", "Pre-School"},
48 {"com.google.chrome.reference", "Reference"},
49 {"com.google.chrome.science", "Science"},
50 {"com.google.chrome.shopping", "Shopping"},
51 {"com.google.chrome.sports", "Sports and Hobbies"},
52 {"com.google.chrome.teens", "Teens"}
55 // Category 0 is "not listed"; actual category IDs start at 1.
56 int GetCategoryId(const std::string& category) {
57 for (size_t i = 0; i < arraysize(g_categories); ++i) {
58 if (g_categories[i].identifier == category)
59 return i + 1;
61 return 0;
64 // Takes a DictionaryValue entry from the JSON file and fills the whitelist
65 // (via URL patterns or hostname hashes) and the URL in the corresponding Site
66 // struct.
67 void AddWhitelistEntries(const base::DictionaryValue* site_dict,
68 SupervisedUserSiteList::Site* site) {
69 std::vector<std::string>* patterns = &site->patterns;
71 bool found = false;
72 const base::ListValue* whitelist = NULL;
73 if (site_dict->GetList(kWhitelistKey, &whitelist)) {
74 found = true;
75 for (const base::Value* entry : *whitelist) {
76 std::string pattern;
77 if (!entry->GetAsString(&pattern)) {
78 LOG(ERROR) << "Invalid whitelist entry";
79 continue;
82 patterns->push_back(pattern);
86 std::vector<std::string>* hashes = &site->hostname_hashes;
87 const base::ListValue* hash_list = NULL;
88 if (site_dict->GetList(kHostnameHashesKey, &hash_list)) {
89 found = true;
90 for (const base::Value* entry : *hash_list) {
91 std::string hash;
92 if (!entry->GetAsString(&hash)) {
93 LOG(ERROR) << "Invalid whitelist entry";
94 continue;
97 hashes->push_back(hash);
101 if (found)
102 return;
104 // Fall back to using a whitelist based on the URL.
105 std::string url_str;
106 if (!site_dict->GetString(kUrlKey, &url_str)) {
107 LOG(ERROR) << "Whitelist is invalid";
108 return;
111 GURL url(url_str);
112 if (!url.is_valid()) {
113 LOG(ERROR) << "URL " << url_str << " is invalid";
114 return;
117 patterns->push_back(url.host());
120 } // namespace
122 SupervisedUserSiteList::Site::Site(const base::string16& name,
123 int category_id)
124 : name(name),
125 category_id(category_id) {}
127 SupervisedUserSiteList::Site::~Site() {}
129 SupervisedUserSiteList::SupervisedUserSiteList(
130 const std::string& extension_id,
131 const base::FilePath& path)
132 : extension_id_(extension_id),
133 path_(path) {
136 SupervisedUserSiteList::~SupervisedUserSiteList() {
139 SupervisedUserSiteList* SupervisedUserSiteList::Clone() const {
140 return new SupervisedUserSiteList(extension_id_, path_);
143 // static
144 void SupervisedUserSiteList::GetCategoryNames(
145 std::vector<base::string16>* categories) {
146 // TODO(bauerb): Collect custom categories from extensions.
147 for (size_t i = 0; i < arraysize(g_categories); ++i) {
148 categories->push_back(base::ASCIIToUTF16(g_categories[i].name));
152 void SupervisedUserSiteList::GetSites(std::vector<Site>* sites) {
153 if (!LazyLoad())
154 return;
156 for (const base::Value* site : *sites_) {
157 const base::DictionaryValue* entry = NULL;
158 if (!site->GetAsDictionary(&entry)) {
159 LOG(ERROR) << "Entry is invalid";
160 continue;
163 base::string16 name;
164 entry->GetString(kNameKey, &name);
166 // TODO(bauerb): We need to distinguish between "no category assigned" and
167 // "not on any site list".
168 int category_id = 0;
169 const base::ListValue* categories = NULL;
170 if (entry->GetList(kCategoriesKey, &categories)) {
171 for (const base::Value* category_entry : *categories) {
172 std::string category;
173 if (!category_entry->GetAsString(&category)) {
174 LOG(ERROR) << "Invalid category";
175 continue;
177 category_id = GetCategoryId(category);
178 break;
181 sites->push_back(Site(name, category_id));
182 AddWhitelistEntries(entry, &sites->back());
186 bool SupervisedUserSiteList::LazyLoad() {
187 if (sites_)
188 return true;
190 JSONFileValueSerializer serializer(path_);
191 std::string error;
192 scoped_ptr<base::Value> value(serializer.Deserialize(NULL, &error));
193 if (!value.get()) {
194 LOG(ERROR) << "Couldn't load site list " << path_.value() << ": "
195 << error;
196 return false;
199 base::DictionaryValue* dict = NULL;
200 if (!value->GetAsDictionary(&dict)) {
201 LOG(ERROR) << "Site list " << path_.value() << " is invalid";
202 return false;
205 int version = 0;
206 if (!dict->GetInteger(kSitelistFormatVersionKey, &version)) {
207 LOG(ERROR) << "Site list " << path_.value() << " has invalid version";
208 return false;
211 if (version > kSitelistFormatVersion) {
212 LOG(ERROR) << "Site list " << path_.value() << " has a too new format";
213 return false;
216 base::ListValue* sites = NULL;
217 if (dict->GetList(kSitesKey, &sites))
218 sites_.reset(sites->DeepCopy());
220 base::DictionaryValue* categories = NULL;
221 if (dict->GetDictionary(kCategoriesKey, &categories))
222 categories_.reset(categories->DeepCopy());
224 return true;
227 void SupervisedUserSiteList::CopyThumbnailUrl(
228 const base::DictionaryValue* source,
229 base::DictionaryValue* dest) {
230 if (!source->HasKey(kThumbnailKey))
231 return;
233 std::string thumbnail;
234 if (!source->GetString(kThumbnailKey, &thumbnail)) {
235 LOG(ERROR) << "Invalid thumbnail";
236 return;
239 GURL base_url =
240 extensions::Extension::GetBaseURLFromExtensionId(extension_id_);
241 GURL thumbnail_url = base_url.Resolve(thumbnail);
242 if (!thumbnail_url.is_valid()) {
243 LOG(ERROR) << "Invalid thumbnail";
244 return;
247 dest->SetString(kThumbnailUrlKey, thumbnail_url.spec());