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

Side by Side Diff: extensions/browser/user_script_loader.cc

Issue 1056533002: Implement <webview>.addContentScript/removeContentScript API [2] (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@webview_addremove_contentscripts_2
Patch Set: nits. Created 5 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
« no previous file with comments | « extensions/browser/user_script_loader.h ('k') | extensions/browser/web_ui_user_script_loader.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « extensions/browser/user_script_loader.h ('k') | extensions/browser/web_ui_user_script_loader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698