OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "extensions/browser/user_script_loader.h" | 5 #include "extensions/browser/user_script_loader.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/files/file_path.h" | |
13 #include "base/files/file_util.h" | |
14 #include "base/version.h" | 10 #include "base/version.h" |
15 #include "content/public/browser/browser_context.h" | 11 #include "content/public/browser/browser_context.h" |
16 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/notification_service.h" | 13 #include "content/public/browser/notification_service.h" |
18 #include "content/public/browser/notification_types.h" | 14 #include "content/public/browser/notification_types.h" |
19 #include "content/public/browser/render_process_host.h" | 15 #include "content/public/browser/render_process_host.h" |
20 #include "extensions/browser/content_verifier.h" | |
21 #include "extensions/browser/extensions_browser_client.h" | 16 #include "extensions/browser/extensions_browser_client.h" |
22 #include "extensions/browser/notification_types.h" | 17 #include "extensions/browser/notification_types.h" |
23 #include "extensions/common/extension_messages.h" | 18 #include "extensions/common/extension_messages.h" |
24 #include "extensions/common/file_util.h" | |
25 | 19 |
26 using content::BrowserThread; | 20 using content::BrowserThread; |
27 using content::BrowserContext; | 21 using content::BrowserContext; |
28 | 22 |
29 namespace extensions { | 23 namespace extensions { |
30 | 24 |
31 namespace { | 25 namespace { |
32 | 26 |
33 using LoadScriptsCallback = | |
34 base::Callback<void(scoped_ptr<UserScriptList>, | |
35 scoped_ptr<base::SharedMemory>)>; | |
36 | |
37 UserScriptLoader::SubstitutionMap* GetLocalizationMessages( | |
38 const UserScriptLoader::HostsInfo& hosts_info, | |
39 const HostID& host_id) { | |
40 UserScriptLoader::HostsInfo::const_iterator iter = hosts_info.find(host_id); | |
41 if (iter == hosts_info.end()) | |
42 return nullptr; | |
43 return file_util::LoadMessageBundleSubstitutionMap( | |
44 iter->second.first, host_id.id(), iter->second.second); | |
45 } | |
46 | |
47 void LoadUserScripts( | |
48 UserScriptList* user_scripts, | |
49 const UserScriptLoader::HostsInfo& hosts_info, | |
50 const std::set<int>& added_script_ids, | |
51 const scoped_refptr<ContentVerifier>& verifier, | |
52 UserScriptLoader::LoadUserScriptsContentFunction callback) { | |
53 for (UserScriptList::iterator script = user_scripts->begin(); | |
54 script != user_scripts->end(); | |
55 ++script) { | |
56 if (added_script_ids.count(script->id()) == 0) | |
57 continue; | |
58 scoped_ptr<UserScriptLoader::SubstitutionMap> localization_messages( | |
59 GetLocalizationMessages(hosts_info, script->host_id())); | |
60 for (size_t k = 0; k < script->js_scripts().size(); ++k) { | |
61 UserScript::File& script_file = script->js_scripts()[k]; | |
62 if (script_file.GetContent().empty()) | |
63 callback.Run(script->host_id(), &script_file, NULL, verifier); | |
64 } | |
65 for (size_t k = 0; k < script->css_scripts().size(); ++k) { | |
66 UserScript::File& script_file = script->css_scripts()[k]; | |
67 if (script_file.GetContent().empty()) | |
68 callback.Run(script->host_id(), &script_file, | |
69 localization_messages.get(), verifier); | |
70 } | |
71 } | |
72 } | |
73 | |
74 // Pickle user scripts and return pointer to the shared memory. | |
75 scoped_ptr<base::SharedMemory> Serialize(const UserScriptList& scripts) { | |
76 Pickle pickle; | |
77 pickle.WriteSizeT(scripts.size()); | |
78 for (UserScriptList::const_iterator script = scripts.begin(); | |
79 script != scripts.end(); | |
80 ++script) { | |
81 // TODO(aa): This can be replaced by sending content script metadata to | |
82 // renderers along with other extension data in ExtensionMsg_Loaded. | |
83 // See crbug.com/70516. | |
84 script->Pickle(&pickle); | |
85 // Write scripts as 'data' so that we can read it out in the slave without | |
86 // allocating a new string. | |
87 for (size_t j = 0; j < script->js_scripts().size(); j++) { | |
88 base::StringPiece contents = script->js_scripts()[j].GetContent(); | |
89 pickle.WriteData(contents.data(), contents.length()); | |
90 } | |
91 for (size_t j = 0; j < script->css_scripts().size(); j++) { | |
92 base::StringPiece contents = script->css_scripts()[j].GetContent(); | |
93 pickle.WriteData(contents.data(), contents.length()); | |
94 } | |
95 } | |
96 | |
97 // Create the shared memory object. | |
98 base::SharedMemory shared_memory; | |
99 | |
100 base::SharedMemoryCreateOptions options; | |
101 options.size = pickle.size(); | |
102 options.share_read_only = true; | |
103 if (!shared_memory.Create(options)) | |
104 return scoped_ptr<base::SharedMemory>(); | |
105 | |
106 if (!shared_memory.Map(pickle.size())) | |
107 return scoped_ptr<base::SharedMemory>(); | |
108 | |
109 // Copy the pickle to shared memory. | |
110 memcpy(shared_memory.memory(), pickle.data(), pickle.size()); | |
111 | |
112 base::SharedMemoryHandle readonly_handle; | |
113 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), | |
114 &readonly_handle)) | |
115 return scoped_ptr<base::SharedMemory>(); | |
116 | |
117 return make_scoped_ptr(new base::SharedMemory(readonly_handle, | |
118 /*read_only=*/true)); | |
119 } | |
120 | |
121 void LoadScriptsOnFileThread( | |
122 scoped_ptr<UserScriptList> user_scripts, | |
123 const UserScriptLoader::HostsInfo& hosts_info, | |
124 const std::set<int>& added_script_ids, | |
125 const scoped_refptr<ContentVerifier>& verifier, | |
126 UserScriptLoader::LoadUserScriptsContentFunction function, | |
127 LoadScriptsCallback callback) { | |
128 DCHECK(user_scripts.get()); | |
129 LoadUserScripts(user_scripts.get(), hosts_info, added_script_ids, | |
130 verifier, function); | |
131 scoped_ptr<base::SharedMemory> memory = Serialize(*user_scripts); | |
132 BrowserThread::PostTask( | |
133 BrowserThread::UI, | |
134 FROM_HERE, | |
135 base::Bind(callback, base::Passed(&user_scripts), base::Passed(&memory))); | |
136 } | |
137 | |
138 // Helper function to parse greasesmonkey headers | 27 // Helper function to parse greasesmonkey headers |
139 bool GetDeclarationValue(const base::StringPiece& line, | 28 bool GetDeclarationValue(const base::StringPiece& line, |
140 const base::StringPiece& prefix, | 29 const base::StringPiece& prefix, |
141 std::string* value) { | 30 std::string* value) { |
142 base::StringPiece::size_type index = line.find(prefix); | 31 base::StringPiece::size_type index = line.find(prefix); |
143 if (index == base::StringPiece::npos) | 32 if (index == base::StringPiece::npos) |
144 return false; | 33 return false; |
145 | 34 |
146 std::string temp(line.data() + index + prefix.length(), | 35 std::string temp(line.data() + index + prefix.length(), |
147 line.length() - index - prefix.length()); | 36 line.length() - index - prefix.length()); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 } | 132 } |
244 | 133 |
245 // If no patterns were specified, default to @include *. This is what | 134 // If no patterns were specified, default to @include *. This is what |
246 // Greasemonkey does. | 135 // Greasemonkey does. |
247 if (script->globs().empty() && script->url_patterns().is_empty()) | 136 if (script->globs().empty() && script->url_patterns().is_empty()) |
248 script->add_glob("*"); | 137 script->add_glob("*"); |
249 | 138 |
250 return true; | 139 return true; |
251 } | 140 } |
252 | 141 |
253 void UserScriptLoader::LoadScriptsForTest(UserScriptList* user_scripts) { | 142 UserScriptLoader::UserScriptLoader(BrowserContext* browser_context, |
254 HostsInfo info; | 143 const HostID& host_id) |
255 std::set<int> added_script_ids; | |
256 for (UserScriptList::iterator it = user_scripts->begin(); | |
257 it != user_scripts->end(); | |
258 ++it) { | |
259 added_script_ids.insert(it->id()); | |
260 } | |
261 LoadUserScripts(user_scripts, info, added_script_ids, | |
262 NULL /* no verifier for testing */, | |
263 GetLoadUserScriptsFunction()); | |
264 } | |
265 | |
266 UserScriptLoader::UserScriptLoader( | |
267 BrowserContext* browser_context, | |
268 const HostID& host_id, | |
269 const scoped_refptr<ContentVerifier>& content_verifier) | |
270 : user_scripts_(new UserScriptList()), | 144 : user_scripts_(new UserScriptList()), |
271 clear_scripts_(false), | 145 clear_scripts_(false), |
272 ready_(false), | 146 ready_(false), |
273 pending_load_(false), | 147 pending_load_(false), |
274 browser_context_(browser_context), | 148 browser_context_(browser_context), |
275 host_id_(host_id), | 149 host_id_(host_id), |
276 content_verifier_(content_verifier), | |
277 weak_factory_(this) { | 150 weak_factory_(this) { |
278 registrar_.Add(this, | 151 registrar_.Add(this, |
279 content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 152 content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
280 content::NotificationService::AllBrowserContextsAndSources()); | 153 content::NotificationService::AllBrowserContextsAndSources()); |
281 } | 154 } |
282 | 155 |
283 UserScriptLoader::~UserScriptLoader() { | 156 UserScriptLoader::~UserScriptLoader() { |
284 } | 157 } |
285 | 158 |
286 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts) { | 159 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts) { |
287 for (std::set<UserScript>::const_iterator it = scripts.begin(); | 160 for (std::set<UserScript>::const_iterator it = scripts.begin(); |
288 it != scripts.end(); | 161 it != scripts.end(); |
289 ++it) { | 162 ++it) { |
290 removed_scripts_.erase(*it); | 163 removed_scripts_.erase(*it); |
291 added_scripts_.insert(*it); | 164 added_scripts_.insert(*it); |
292 } | 165 } |
293 AttemptLoad(); | 166 AttemptLoad(); |
294 } | 167 } |
295 | 168 |
| 169 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts, |
| 170 int render_process_id, |
| 171 int render_view_id) { |
| 172 AddScripts(scripts); |
| 173 } |
| 174 |
296 void UserScriptLoader::RemoveScripts(const std::set<UserScript>& scripts) { | 175 void UserScriptLoader::RemoveScripts(const std::set<UserScript>& scripts) { |
297 for (std::set<UserScript>::const_iterator it = scripts.begin(); | 176 for (std::set<UserScript>::const_iterator it = scripts.begin(); |
298 it != scripts.end(); | 177 it != scripts.end(); |
299 ++it) { | 178 ++it) { |
300 added_scripts_.erase(*it); | 179 added_scripts_.erase(*it); |
301 removed_scripts_.insert(*it); | 180 removed_scripts_.insert(*it); |
302 } | 181 } |
303 AttemptLoad(); | 182 AttemptLoad(); |
304 } | 183 } |
305 | 184 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 } | 254 } |
376 | 255 |
377 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in | 256 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in |
378 // its IPC message. This must be done before we clear |added_scripts_| and | 257 // its IPC message. This must be done before we clear |added_scripts_| and |
379 // |removed_scripts_| below. | 258 // |removed_scripts_| below. |
380 std::set<UserScript> changed_scripts(added_scripts_); | 259 std::set<UserScript> changed_scripts(added_scripts_); |
381 changed_scripts.insert(removed_scripts_.begin(), removed_scripts_.end()); | 260 changed_scripts.insert(removed_scripts_.begin(), removed_scripts_.end()); |
382 for (const UserScript& script : changed_scripts) | 261 for (const UserScript& script : changed_scripts) |
383 changed_hosts_.insert(script.host_id()); | 262 changed_hosts_.insert(script.host_id()); |
384 | 263 |
385 // |changed_hosts_| before passing it to LoadScriptsOnFileThread. | 264 LoadScripts(user_scripts_.Pass(), changed_hosts_, added_script_ids, |
386 UpdateHostsInfo(changed_hosts_); | 265 base::Bind(&UserScriptLoader::OnScriptsLoaded, |
387 | 266 weak_factory_.GetWeakPtr())); |
388 BrowserThread::PostTask( | |
389 BrowserThread::FILE, FROM_HERE, | |
390 base::Bind(&LoadScriptsOnFileThread, base::Passed(&user_scripts_), | |
391 hosts_info_, added_script_ids, content_verifier_, | |
392 GetLoadUserScriptsFunction(), | |
393 base::Bind(&UserScriptLoader::OnScriptsLoaded, | |
394 weak_factory_.GetWeakPtr()))); | |
395 | 267 |
396 clear_scripts_ = false; | 268 clear_scripts_ = false; |
397 added_scripts_.clear(); | 269 added_scripts_.clear(); |
398 removed_scripts_.clear(); | 270 removed_scripts_.clear(); |
399 user_scripts_.reset(NULL); | 271 user_scripts_.reset(); |
400 } | 272 } |
401 | 273 |
402 void UserScriptLoader::AddHostInfo(const HostID& host_id, | 274 // static |
403 const PathAndDefaultLocale& location) { | 275 scoped_ptr<base::SharedMemory> UserScriptLoader::Serialize( |
404 if (hosts_info_.find(host_id) != hosts_info_.end()) | 276 const UserScriptList& scripts) { |
405 return; | 277 Pickle pickle; |
406 hosts_info_[host_id] = location; | 278 pickle.WriteSizeT(scripts.size()); |
407 } | 279 for (const UserScript& script : scripts) { |
| 280 // TODO(aa): This can be replaced by sending content script metadata to |
| 281 // renderers along with other extension data in ExtensionMsg_Loaded. |
| 282 // See crbug.com/70516. |
| 283 script.Pickle(&pickle); |
| 284 // Write scripts as 'data' so that we can read it out in the slave without |
| 285 // allocating a new string. |
| 286 for (const UserScript::File& script_file : script.js_scripts()) { |
| 287 base::StringPiece contents = script_file.GetContent(); |
| 288 pickle.WriteData(contents.data(), contents.length()); |
| 289 } |
| 290 for (const UserScript::File& script_file : script.css_scripts()) { |
| 291 base::StringPiece contents = script_file.GetContent(); |
| 292 pickle.WriteData(contents.data(), contents.length()); |
| 293 } |
| 294 } |
408 | 295 |
409 void UserScriptLoader::RemoveHostInfo(const HostID& host_id) { | 296 // Create the shared memory object. |
410 hosts_info_.erase(host_id); | 297 base::SharedMemory shared_memory; |
| 298 |
| 299 base::SharedMemoryCreateOptions options; |
| 300 options.size = pickle.size(); |
| 301 options.share_read_only = true; |
| 302 if (!shared_memory.Create(options)) |
| 303 return scoped_ptr<base::SharedMemory>(); |
| 304 |
| 305 if (!shared_memory.Map(pickle.size())) |
| 306 return scoped_ptr<base::SharedMemory>(); |
| 307 |
| 308 // Copy the pickle to shared memory. |
| 309 memcpy(shared_memory.memory(), pickle.data(), pickle.size()); |
| 310 |
| 311 base::SharedMemoryHandle readonly_handle; |
| 312 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), |
| 313 &readonly_handle)) |
| 314 return scoped_ptr<base::SharedMemory>(); |
| 315 |
| 316 return make_scoped_ptr(new base::SharedMemory(readonly_handle, |
| 317 /*read_only=*/true)); |
411 } | 318 } |
412 | 319 |
413 void UserScriptLoader::SetReady(bool ready) { | 320 void UserScriptLoader::SetReady(bool ready) { |
414 bool was_ready = ready_; | 321 bool was_ready = ready_; |
415 ready_ = ready; | 322 ready_ = ready; |
416 if (ready_ && !was_ready) | 323 if (ready_ && !was_ready) |
417 AttemptLoad(); | 324 AttemptLoad(); |
418 } | 325 } |
419 | 326 |
420 void UserScriptLoader::OnScriptsLoaded( | 327 void UserScriptLoader::OnScriptsLoaded( |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) | 386 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) |
480 return; // This can legitimately fail if the renderer asserts at startup. | 387 return; // This can legitimately fail if the renderer asserts at startup. |
481 | 388 |
482 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | 389 if (base::SharedMemory::IsHandleValid(handle_for_process)) { |
483 process->Send(new ExtensionMsg_UpdateUserScripts(handle_for_process, | 390 process->Send(new ExtensionMsg_UpdateUserScripts(handle_for_process, |
484 host_id(), changed_hosts)); | 391 host_id(), changed_hosts)); |
485 } | 392 } |
486 } | 393 } |
487 | 394 |
488 } // namespace extensions | 395 } // namespace extensions |
OLD | NEW |