Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: chrome/browser/extensions/external_pref_extension_loader.cc

Issue 9963120: Introduces an additional extension loader that load extra extensions based on per-extension json fi… (Closed) Base URL: https://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/external_pref_extension_loader.h" 5 #include "chrome/browser/extensions/external_pref_extension_loader.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/dir_reader_posix.h"
8 #include "base/file_path.h" 9 #include "base/file_path.h"
9 #include "base/file_util.h" 10 #include "base/file_util.h"
10 #include "base/json/json_file_value_serializer.h" 11 #include "base/json/json_file_value_serializer.h"
11 #include "base/json/json_string_value_serializer.h" 12 #include "base/json/json_string_value_serializer.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
14 #include "base/path_service.h" 15 #include "base/path_service.h"
15 #include "chrome/common/chrome_paths.h" 16 #include "chrome/common/chrome_paths.h"
16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/browser_thread.h"
17 18
18 using content::BrowserThread; 19 using content::BrowserThread;
19 20
20 namespace { 21 namespace {
21 22
23 std::set<FilePath> GetPrefsCandidateFilesFromFolder(
24 const FilePath& external_extension_search_path) {
25 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
26
27 std::set<FilePath> external_extension_paths;
28
29 if (!file_util::PathExists(external_extension_search_path)) {
30 // Does not have to exist.
31 return external_extension_paths;
32 }
33
34 base::DirReaderPosix
35 reader(external_extension_search_path.value().c_str());
36
37 if (!reader.IsValid()) {
38 LOG(ERROR) << "Can not read external extensions path '"
39 << external_extension_search_path.LossyDisplayName()
40 << "' although it appears to exist.";
41 return external_extension_paths;
42 }
43
44 while (reader.Next()) {
45 const FilePath filename(reader.name());
46
47 if (filename.MatchesExtension(".json")) {
48 external_extension_paths.insert(filename);
49 } else {
50 DVLOG(1) << "Not considering: " << reader.name()
51 << " (does not have a .json extension)";
52 }
53 }
54
55 return external_extension_paths;
56 }
57
58 // Extracts/expect a file content in json format.
Finnur 2012/04/27 10:50:28 Suggest: Extracts extension information from a jso
Alexandre Abreu 2012/04/27 14:05:40 Done.
59 // An empty dictionary is returned in case of failure (e.g. invalid
60 // path or json content).
22 // Caller takes ownership of the returned dictionary. 61 // Caller takes ownership of the returned dictionary.
23 DictionaryValue* ExtractPrefs(const FilePath& path, 62 DictionaryValue* ExtractExtensionPrefs(
24 base::ValueSerializer* serializer) { 63 const FilePath& path,
64 base::ValueSerializer* serializer) {
25 std::string error_msg; 65 std::string error_msg;
26 Value* extensions = serializer->Deserialize(NULL, &error_msg); 66 Value* extensions = serializer->Deserialize(NULL, &error_msg);
27 if (!extensions) { 67 if (!extensions) {
28 LOG(WARNING) << "Unable to deserialize json data: " << error_msg 68 LOG(WARNING) << "Unable to deserialize json data: " << error_msg
29 << " In file " << path.value() << " ."; 69 << " in file " << path.value() << ".";
30 } else { 70 return new DictionaryValue;
31 if (!extensions->IsType(Value::TYPE_DICTIONARY)) {
32 LOG(WARNING) << "Expected a JSON dictionary in file "
33 << path.value() << " .";
34 } else {
35 return static_cast<DictionaryValue*>(extensions);
36 }
37 } 71 }
72
73 DictionaryValue* ext_dictionary = NULL;
74 if (extensions->GetAsDictionary(&ext_dictionary))
75 return ext_dictionary;
76
77 LOG(WARNING) << "Expected a JSON dictionary in file "
78 << path.value() << ".";
38 return new DictionaryValue; 79 return new DictionaryValue;
39 } 80 }
40 81
41 } // namespace 82 } // namespace {
42 83
43 ExternalPrefExtensionLoader::ExternalPrefExtensionLoader(int base_path_key, 84 ExternalPrefExtensionLoader::ExternalPrefExtensionLoader(int base_path_id,
44 Options options) 85 Options options)
45 : base_path_key_(base_path_key), 86 : base_path_id_(base_path_id),
46 options_(options){ 87 options_(options) {
47 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 88 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
48 } 89 }
49 90
50 const FilePath ExternalPrefExtensionLoader::GetBaseCrxFilePath() { 91 const FilePath ExternalPrefExtensionLoader::GetBaseCrxFilePath() {
51 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 92 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52 93
53 // |base_path_| was set in LoadOnFileThread(). 94 // |base_path_| was set in LoadOnFileThread().
54 return base_path_; 95 return base_path_;
55 } 96 }
56 97
57 void ExternalPrefExtensionLoader::StartLoading() { 98 void ExternalPrefExtensionLoader::StartLoading() {
58 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 99 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 BrowserThread::PostTask( 100 BrowserThread::PostTask(
60 BrowserThread::FILE, FROM_HERE, 101 BrowserThread::FILE, FROM_HERE,
61 base::Bind(&ExternalPrefExtensionLoader::LoadOnFileThread, this)); 102 base::Bind(&ExternalPrefExtensionLoader::LoadOnFileThread, this));
62 } 103 }
63 104
64 DictionaryValue* ExternalPrefExtensionLoader::ReadJsonPrefsFile() { 105 void ExternalPrefExtensionLoader::LoadOnFileThread() {
65 // TODO(skerner): Some values of base_path_key_ will cause 106 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
107
108 // TODO(skerner): Some values of base_path_id_ will cause
66 // PathService::Get() to return false, because the path does 109 // PathService::Get() to return false, because the path does
67 // not exist. Find and fix the build/install scripts so that 110 // not exist. Find and fix the build/install scripts so that
68 // this can become a CHECK(). Known examples include chrome 111 // this can become a CHECK(). Known examples include chrome
69 // OS developer builds and linux install packages. 112 // OS developer builds and linux install packages.
70 // Tracked as crbug.com/70402 . 113 // Tracked as crbug.com/70402 .
71 if (!PathService::Get(base_path_key_, &base_path_)) { 114 if (!PathService::Get(base_path_id_, &base_path_)) {
72 return NULL; 115 return;
73 } 116 }
Finnur 2012/04/27 10:50:28 nit: Avoid braces for single line if clauses.
Alexandre Abreu 2012/04/27 14:05:40 Done.
74 117
118 scoped_ptr<DictionaryValue> prefs(new DictionaryValue);
119
120 ReadExternalExtensionPrefFile(prefs.get());
Finnur 2012/04/27 10:50:28 Can you add a warning, something like: if (!prefs.
Alexandre Abreu 2012/04/27 14:05:40 Done.
121 ReadStandaloneExtensionPrefFiles(prefs.get());
Finnur 2012/04/27 10:50:28 Just to be clear: The format of the |prefs| dictio
Alexandre Abreu 2012/04/27 14:05:40 Yes,
122
123 prefs_.reset(prefs.release());
124 if (!prefs_.get())
125 prefs_.reset(new DictionaryValue());
126
127 if (base_path_id_ == chrome::DIR_EXTERNAL_EXTENSIONS) {
128 UMA_HISTOGRAM_COUNTS_100("Extensions.ExternalJsonCount",
129 prefs_->size());
130 }
131
132 // If we have any records to process, then we must have
133 // read at least one .json file. If so, then we should have
134 // set |base_path_|.
135 if (!prefs_->empty())
136 CHECK(!base_path_.empty());
137
138 BrowserThread::PostTask(
139 BrowserThread::UI, FROM_HERE,
140 base::Bind(&ExternalPrefExtensionLoader::LoadFinished, this));
141 }
142
143 void ExternalPrefExtensionLoader::ReadExternalExtensionPrefFile(
144 DictionaryValue* prefs) {
145 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
146 CHECK(NULL != prefs);
147
75 FilePath json_file = base_path_.Append( 148 FilePath json_file = base_path_.Append(
76 FILE_PATH_LITERAL("external_extensions.json")); 149 FILE_PATH_LITERAL("external_extensions.json"));
77 150
78 if (!file_util::PathExists(json_file)) { 151 if (!file_util::PathExists(json_file)) {
79 // This is not an error. The file does not exist by default. 152 // This is not an error. The file does not exist by default.
80 return NULL; 153 return;
81 } 154 }
82 155
83 if (IsOptionSet(ENSURE_PATH_CONTROLLED_BY_ADMIN)) { 156 if (IsOptionSet(ENSURE_PATH_CONTROLLED_BY_ADMIN)) {
84 #if defined(OS_MACOSX) 157 #if defined(OS_MACOSX)
85 if (!file_util::VerifyPathControlledByAdmin(json_file)) { 158 if (!file_util::VerifyPathControlledByAdmin(json_file)) {
86 LOG(ERROR) << "Can not read external extensions source. The file " 159 LOG(ERROR) << "Can not read external extensions source. The file "
87 << json_file.value() << " and every directory in its path, " 160 << json_file.value() << " and every directory in its path, "
88 << "must be owned by root, have group \"admin\", and not be " 161 << "must be owned by root, have group \"admin\", and not be "
89 << "writable by all users. These restrictions prevent " 162 << "writable by all users. These restrictions prevent "
90 << "unprivleged users from making chrome install extensions " 163 << "unprivleged users from making chrome install extensions "
91 << "on other users' accounts."; 164 << "on other users' accounts.";
92 return NULL; 165 return NULL;
93 } 166 }
94 #else 167 #else
95 // The only platform that uses this check is Mac OS. If you add one, 168 // The only platform that uses this check is Mac OS. If you add one,
96 // you need to implement file_util::VerifyPathControlledByAdmin() for 169 // you need to implement file_util::VerifyPathControlledByAdmin() for
97 // that platform. 170 // that platform.
98 NOTREACHED(); 171 NOTREACHED();
99 #endif // defined(OS_MACOSX) 172 #endif // defined(OS_MACOSX)
100 } 173 }
101 174
102 JSONFileValueSerializer serializer(json_file); 175 JSONFileValueSerializer serializer(json_file);
103 DictionaryValue* parsed_json_prefs = ExtractPrefs(json_file, &serializer); 176 DictionaryValue * ext_prefs = ExtractExtensionPrefs(json_file, &serializer);
104 return parsed_json_prefs; 177 if (NULL != ext_prefs)
Finnur 2012/04/27 10:50:28 nit: if (ext_prefs)
Alexandre Abreu 2012/04/27 14:05:40 Done.
178 prefs->MergeDictionary(ext_prefs);
105 } 179 }
106 180
107 void ExternalPrefExtensionLoader::LoadOnFileThread() { 181 void ExternalPrefExtensionLoader::ReadStandaloneExtensionPrefFiles(
182 DictionaryValue* prefs) {
108 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 183 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
184 CHECK(NULL != prefs);
109 185
110 prefs_.reset(ReadJsonPrefsFile()); 186 // First list the potential .json candidates.
111 if (!prefs_.get()) 187 std::set<FilePath>
112 prefs_.reset(new DictionaryValue()); 188 candidates = GetPrefsCandidateFilesFromFolder(base_path_);
113 189 if (candidates.empty()) {
114 if (base_path_key_ == chrome::DIR_EXTERNAL_EXTENSIONS) { 190 DVLOG(1) << "Extension candidates list empty";
115 UMA_HISTOGRAM_COUNTS_100("Extensions.ExternalJsonCount", 191 return;
116 prefs_->size());
117 } 192 }
118 193
119 // If we have any records to process, then we must have 194 // For each file read the json description & build the proper
120 // read the .json file. If we read the .json file, then 195 // associated prefs.
121 // we were should have set |base_path_|. 196 for (std::set<FilePath>::const_iterator it = candidates.begin();
122 if (!prefs_->empty()) 197 it != candidates.end();
123 CHECK(!base_path_.empty()); 198 ++it) {
199 FilePath extension_candidate_path = base_path_.Append(*it);
124 200
125 BrowserThread::PostTask( 201 FilePath::StringType id =
126 BrowserThread::UI, FROM_HERE, 202 extension_candidate_path.RemoveExtension().BaseName().value();
127 base::Bind(&ExternalPrefExtensionLoader::LoadFinished, this)); 203
204 DVLOG(1) << "Reading json file: " << extension_candidate_path.value();
205
206 JSONFileValueSerializer serializer(extension_candidate_path);
207 DictionaryValue* ext_prefs =
208 ExtractExtensionPrefs(extension_candidate_path,
209 &serializer);
210
211 if (NULL != ext_prefs) {
Finnur 2012/04/27 10:50:28 nit: if (ext_prefs)
Alexandre Abreu 2012/04/27 14:05:40 Done.
212 DVLOG(1) << "Adding extension with id: " << id;
213
Finnur 2012/04/27 10:50:28 nit: delete this extra linebreak?
Alexandre Abreu 2012/04/27 14:05:40 Done.
214 prefs->Set(id, ext_prefs);
215 }
216 }
128 } 217 }
129 218
130 ExternalTestingExtensionLoader::ExternalTestingExtensionLoader( 219 ExternalTestingExtensionLoader::ExternalTestingExtensionLoader(
131 const std::string& json_data, 220 const std::string& json_data,
132 const FilePath& fake_base_path) 221 const FilePath& fake_base_path)
133 : fake_base_path_(fake_base_path) { 222 : fake_base_path_(fake_base_path) {
134 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 223 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135 JSONStringValueSerializer serializer(json_data); 224 JSONStringValueSerializer serializer(json_data);
136 FilePath fake_json_path = fake_base_path.AppendASCII("fake.json"); 225 FilePath fake_json_path = fake_base_path.AppendASCII("fake.json");
137 testing_prefs_.reset(ExtractPrefs(fake_json_path, &serializer)); 226 testing_prefs_.reset(ExtractExtensionPrefs(fake_json_path, &serializer));
138 } 227 }
139 228
140 void ExternalTestingExtensionLoader::StartLoading() { 229 void ExternalTestingExtensionLoader::StartLoading() {
141 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 230 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
142 prefs_.reset(testing_prefs_->DeepCopy()); 231 prefs_.reset(testing_prefs_->DeepCopy());
143 LoadFinished(); 232 LoadFinished();
144 } 233 }
145 234
146 ExternalTestingExtensionLoader::~ExternalTestingExtensionLoader() {} 235 ExternalTestingExtensionLoader::~ExternalTestingExtensionLoader() {}
147 236
148 const FilePath ExternalTestingExtensionLoader::GetBaseCrxFilePath() { 237 const FilePath ExternalTestingExtensionLoader::GetBaseCrxFilePath() {
149 return fake_base_path_; 238 return fake_base_path_;
150 } 239 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698