| OLD | NEW |
| 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/user_script_master.h" | 5 #include "chrome/browser/extensions/user_script_master.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/memory/shared_memory.h" | 13 #include "base/memory/shared_memory.h" |
| 14 #include "base/version.h" | 14 #include "base/version.h" |
| 15 #include "chrome/browser/chrome_notification_types.h" | 15 #include "chrome/browser/chrome_notification_types.h" |
| 16 #include "chrome/browser/extensions/extension_util.h" | 16 #include "chrome/browser/extensions/extension_util.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 18 #include "chrome/common/extensions/api/i18n/default_locale_handler.h" | |
| 19 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" | 18 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" |
| 20 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
| 21 #include "content/public/browser/render_process_host.h" | 20 #include "content/public/browser/render_process_host.h" |
| 22 #include "extensions/browser/component_extension_resource_manager.h" | 21 #include "extensions/browser/component_extension_resource_manager.h" |
| 23 #include "extensions/browser/content_verifier.h" | 22 #include "extensions/browser/content_verifier.h" |
| 24 #include "extensions/browser/extension_registry.h" | 23 #include "extensions/browser/extension_registry.h" |
| 25 #include "extensions/browser/extension_system.h" | 24 #include "extensions/browser/extension_system.h" |
| 26 #include "extensions/browser/extensions_browser_client.h" | 25 #include "extensions/browser/extensions_browser_client.h" |
| 27 #include "extensions/common/file_util.h" | 26 #include "extensions/common/file_util.h" |
| 28 #include "extensions/common/message_bundle.h" | 27 #include "extensions/common/message_bundle.h" |
| 29 #include "ui/base/resource/resource_bundle.h" | 28 #include "ui/base/resource/resource_bundle.h" |
| 30 | 29 |
| 31 using content::BrowserThread; | 30 using content::BrowserThread; |
| 32 using extensions::ExtensionsBrowserClient; | 31 using extensions::ExtensionsBrowserClient; |
| 33 | 32 |
| 34 namespace extensions { | 33 namespace extensions { |
| 35 | 34 |
| 36 namespace { | 35 namespace { |
| 37 | 36 |
| 38 typedef base::Callback<void(scoped_ptr<UserScriptList>, | |
| 39 scoped_ptr<base::SharedMemory>)> | |
| 40 LoadScriptsCallback; | |
| 41 | |
| 42 void VerifyContent(scoped_refptr<ContentVerifier> verifier, | 37 void VerifyContent(scoped_refptr<ContentVerifier> verifier, |
| 43 const std::string& extension_id, | 38 const std::string& extension_id, |
| 44 const base::FilePath& extension_root, | 39 const base::FilePath& extension_root, |
| 45 const base::FilePath& relative_path, | 40 const base::FilePath& relative_path, |
| 46 const std::string& content) { | 41 const std::string& content) { |
| 47 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 42 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 48 scoped_refptr<ContentVerifyJob> job( | 43 scoped_refptr<ContentVerifyJob> job( |
| 49 verifier->CreateJobFor(extension_id, extension_root, relative_path)); | 44 verifier->CreateJobFor(extension_id, extension_root, relative_path)); |
| 50 if (job.get()) { | 45 if (job.get()) { |
| 51 job->Start(); | 46 job->Start(); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 | 185 |
| 191 base::SharedMemoryHandle readonly_handle; | 186 base::SharedMemoryHandle readonly_handle; |
| 192 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), | 187 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), |
| 193 &readonly_handle)) | 188 &readonly_handle)) |
| 194 return scoped_ptr<base::SharedMemory>(); | 189 return scoped_ptr<base::SharedMemory>(); |
| 195 | 190 |
| 196 return make_scoped_ptr(new base::SharedMemory(readonly_handle, | 191 return make_scoped_ptr(new base::SharedMemory(readonly_handle, |
| 197 /*read_only=*/true)); | 192 /*read_only=*/true)); |
| 198 } | 193 } |
| 199 | 194 |
| 200 void LoadScriptsOnFileThread(scoped_ptr<UserScriptList> user_scripts, | |
| 201 const ExtensionsInfo& extensions_info, | |
| 202 const std::set<std::string>& new_extensions, | |
| 203 scoped_refptr<ContentVerifier> verifier, | |
| 204 LoadScriptsCallback callback) { | |
| 205 DCHECK(user_scripts.get()); | |
| 206 LoadUserScripts( | |
| 207 user_scripts.get(), extensions_info, new_extensions, verifier); | |
| 208 scoped_ptr<base::SharedMemory> memory = Serialize(*user_scripts); | |
| 209 BrowserThread::PostTask( | |
| 210 BrowserThread::UI, | |
| 211 FROM_HERE, | |
| 212 base::Bind(callback, | |
| 213 base::Passed(&user_scripts), | |
| 214 base::Passed(&memory))); | |
| 215 } | |
| 216 | |
| 217 // Helper function to parse greasesmonkey headers | 195 // Helper function to parse greasesmonkey headers |
| 218 bool GetDeclarationValue(const base::StringPiece& line, | 196 bool GetDeclarationValue(const base::StringPiece& line, |
| 219 const base::StringPiece& prefix, | 197 const base::StringPiece& prefix, |
| 220 std::string* value) { | 198 std::string* value) { |
| 221 base::StringPiece::size_type index = line.find(prefix); | 199 base::StringPiece::size_type index = line.find(prefix); |
| 222 if (index == base::StringPiece::npos) | 200 if (index == base::StringPiece::npos) |
| 223 return false; | 201 return false; |
| 224 | 202 |
| 225 std::string temp(line.data() + index + prefix.length(), | 203 std::string temp(line.data() + index + prefix.length(), |
| 226 line.length() - index - prefix.length()); | 204 line.length() - index - prefix.length()); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 std::set<std::string> new_extensions; | 313 std::set<std::string> new_extensions; |
| 336 for (UserScriptList::const_iterator iter = user_scripts->begin(); | 314 for (UserScriptList::const_iterator iter = user_scripts->begin(); |
| 337 iter != user_scripts->end(); | 315 iter != user_scripts->end(); |
| 338 ++iter) { | 316 ++iter) { |
| 339 new_extensions.insert(iter->extension_id()); | 317 new_extensions.insert(iter->extension_id()); |
| 340 } | 318 } |
| 341 LoadUserScripts( | 319 LoadUserScripts( |
| 342 user_scripts, info, new_extensions, NULL /* no verifier for testing */); | 320 user_scripts, info, new_extensions, NULL /* no verifier for testing */); |
| 343 } | 321 } |
| 344 | 322 |
| 323 // static |
| 324 void UserScriptMaster::LoadScriptsOnFileThread( |
| 325 scoped_ptr<UserScriptList> user_scripts, |
| 326 const ExtensionsInfo& extensions_info, |
| 327 const std::set<std::string>& new_extensions, |
| 328 scoped_refptr<ContentVerifier> verifier, |
| 329 LoadScriptsCallback callback) { |
| 330 DCHECK(user_scripts.get()); |
| 331 LoadUserScripts( |
| 332 user_scripts.get(), extensions_info, new_extensions, verifier); |
| 333 scoped_ptr<base::SharedMemory> memory = Serialize(*user_scripts); |
| 334 BrowserThread::PostTask( |
| 335 BrowserThread::UI, |
| 336 FROM_HERE, |
| 337 base::Bind(callback, base::Passed(&user_scripts), base::Passed(&memory))); |
| 338 } |
| 339 |
| 345 UserScriptMaster::UserScriptMaster(Profile* profile) | 340 UserScriptMaster::UserScriptMaster(Profile* profile) |
| 346 : user_scripts_(new UserScriptList()), | 341 : user_scripts_(new UserScriptList()), |
| 347 extensions_service_ready_(false), | 342 extensions_service_ready_(false), |
| 348 pending_load_(false), | 343 pending_load_(false), |
| 349 profile_(profile), | 344 profile_(profile), |
| 350 extension_registry_observer_(this), | |
| 351 weak_factory_(this) { | 345 weak_factory_(this) { |
| 352 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); | |
| 353 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, | |
| 354 content::Source<Profile>(profile_)); | |
| 355 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | |
| 356 content::NotificationService::AllBrowserContextsAndSources()); | |
| 357 } | 346 } |
| 358 | 347 |
| 359 UserScriptMaster::~UserScriptMaster() { | 348 UserScriptMaster::~UserScriptMaster() { |
| 360 } | 349 } |
| 361 | 350 |
| 362 void UserScriptMaster::OnScriptsLoaded( | 351 void UserScriptMaster::OnScriptsLoaded( |
| 363 scoped_ptr<UserScriptList> user_scripts, | 352 scoped_ptr<UserScriptList> user_scripts, |
| 364 scoped_ptr<base::SharedMemory> shared_memory) { | 353 scoped_ptr<base::SharedMemory> shared_memory) { |
| 365 user_scripts_.reset(user_scripts.release()); | 354 user_scripts_.reset(user_scripts.release()); |
| 366 if (pending_load_) { | 355 if (pending_load_) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 394 changed_extensions_); | 383 changed_extensions_); |
| 395 } | 384 } |
| 396 changed_extensions_.clear(); | 385 changed_extensions_.clear(); |
| 397 | 386 |
| 398 content::NotificationService::current()->Notify( | 387 content::NotificationService::current()->Notify( |
| 399 chrome::NOTIFICATION_USER_SCRIPTS_UPDATED, | 388 chrome::NOTIFICATION_USER_SCRIPTS_UPDATED, |
| 400 content::Source<Profile>(profile_), | 389 content::Source<Profile>(profile_), |
| 401 content::Details<base::SharedMemory>(shared_memory_.get())); | 390 content::Details<base::SharedMemory>(shared_memory_.get())); |
| 402 } | 391 } |
| 403 | 392 |
| 404 void UserScriptMaster::OnExtensionLoaded( | |
| 405 content::BrowserContext* browser_context, | |
| 406 const Extension* extension) { | |
| 407 added_extensions_.insert(extension->id()); | |
| 408 removed_extensions_.erase(extension->id()); | |
| 409 extensions_info_[extension->id()] = | |
| 410 ExtensionSet::ExtensionPathAndDefaultLocale( | |
| 411 extension->path(), LocaleInfo::GetDefaultLocale(extension)); | |
| 412 if (extensions_service_ready_) { | |
| 413 changed_extensions_.insert(extension->id()); | |
| 414 if (is_loading()) | |
| 415 pending_load_ = true; | |
| 416 else | |
| 417 StartLoad(); | |
| 418 } | |
| 419 } | |
| 420 | |
| 421 void UserScriptMaster::OnExtensionUnloaded( | |
| 422 content::BrowserContext* browser_context, | |
| 423 const Extension* extension, | |
| 424 UnloadedExtensionInfo::Reason reason) { | |
| 425 removed_extensions_.insert(extension->id()); | |
| 426 added_extensions_.erase(extension->id()); | |
| 427 // Remove any content scripts. | |
| 428 extensions_info_.erase(extension->id()); | |
| 429 changed_extensions_.insert(extension->id()); | |
| 430 if (is_loading()) | |
| 431 pending_load_ = true; | |
| 432 else | |
| 433 StartLoad(); | |
| 434 } | |
| 435 | |
| 436 void UserScriptMaster::Observe(int type, | |
| 437 const content::NotificationSource& source, | |
| 438 const content::NotificationDetails& details) { | |
| 439 bool should_start_load = false; | |
| 440 switch (type) { | |
| 441 case chrome::NOTIFICATION_EXTENSIONS_READY: | |
| 442 extensions_service_ready_ = true; | |
| 443 should_start_load = true; | |
| 444 break; | |
| 445 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: { | |
| 446 content::RenderProcessHost* process = | |
| 447 content::Source<content::RenderProcessHost>(source).ptr(); | |
| 448 Profile* profile = Profile::FromBrowserContext( | |
| 449 process->GetBrowserContext()); | |
| 450 if (!profile_->IsSameProfile(profile)) | |
| 451 return; | |
| 452 if (ScriptsReady()) { | |
| 453 SendUpdate(process, | |
| 454 GetSharedMemory(), | |
| 455 std::set<std::string>()); // Include all extensions. | |
| 456 } | |
| 457 break; | |
| 458 } | |
| 459 default: | |
| 460 DCHECK(false); | |
| 461 } | |
| 462 | |
| 463 if (should_start_load) { | |
| 464 if (is_loading()) | |
| 465 pending_load_ = true; | |
| 466 else | |
| 467 StartLoad(); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 void UserScriptMaster::StartLoad() { | |
| 472 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 473 DCHECK(!is_loading()); | |
| 474 | |
| 475 // Remove any user scripts belonging to any extension that was updated or | |
| 476 // removed. | |
| 477 for (UserScriptList::iterator iter = user_scripts_->begin(); | |
| 478 iter != user_scripts_->end();) { | |
| 479 if (removed_extensions_.count(iter->extension_id()) > 0 || | |
| 480 added_extensions_.count(iter->extension_id()) > 0) { | |
| 481 iter = user_scripts_->erase(iter); | |
| 482 } else { | |
| 483 ++iter; | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 // Add any content scripts for extensions that were recently loaded. | |
| 488 const ExtensionSet& enabled_extensions = | |
| 489 ExtensionRegistry::Get(profile_)->enabled_extensions(); | |
| 490 for (std::set<std::string>::const_iterator iter = added_extensions_.begin(); | |
| 491 iter != added_extensions_.end(); ++iter) { | |
| 492 const Extension* extension = enabled_extensions.GetByID(*iter); | |
| 493 if (!extension) | |
| 494 continue; | |
| 495 bool incognito_enabled = | |
| 496 util::IsIncognitoEnabled(extension->id(), profile_); | |
| 497 const UserScriptList& scripts = | |
| 498 ContentScriptsInfo::GetContentScripts(extension); | |
| 499 for (UserScriptList::const_iterator script = scripts.begin(); | |
| 500 script != scripts.end(); | |
| 501 ++script) { | |
| 502 user_scripts_->push_back(*script); | |
| 503 user_scripts_->back().set_incognito_enabled(incognito_enabled); | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 BrowserThread::PostTask( | |
| 508 BrowserThread::FILE, | |
| 509 FROM_HERE, | |
| 510 base::Bind(&LoadScriptsOnFileThread, | |
| 511 base::Passed(&user_scripts_), | |
| 512 extensions_info_, | |
| 513 added_extensions_, | |
| 514 make_scoped_refptr( | |
| 515 ExtensionSystem::Get(profile_)->content_verifier()), | |
| 516 base::Bind(&UserScriptMaster::OnScriptsLoaded, | |
| 517 weak_factory_.GetWeakPtr()))); | |
| 518 added_extensions_.clear(); | |
| 519 removed_extensions_.clear(); | |
| 520 user_scripts_.reset(NULL); | |
| 521 } | |
| 522 | |
| 523 void UserScriptMaster::SendUpdate( | 393 void UserScriptMaster::SendUpdate( |
| 524 content::RenderProcessHost* process, | 394 content::RenderProcessHost* process, |
| 525 base::SharedMemory* shared_memory, | 395 base::SharedMemory* shared_memory, |
| 526 const std::set<std::string>& changed_extensions) { | 396 const std::set<std::string>& changed_extensions) { |
| 527 // Don't allow injection of content scripts into <webview>. | 397 // Don't allow injection of content scripts into <webview>. |
| 528 if (process->IsIsolatedGuest()) | 398 if (process->IsIsolatedGuest()) |
| 529 return; | 399 return; |
| 530 | 400 |
| 531 Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); | 401 Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); |
| 532 // Make sure we only send user scripts to processes in our profile. | 402 // Make sure we only send user scripts to processes in our profile. |
| 533 if (!profile_->IsSameProfile(profile)) | 403 if (!profile_->IsSameProfile(profile)) |
| 534 return; | 404 return; |
| 535 | 405 |
| 536 // If the process is being started asynchronously, early return. We'll end up | 406 // If the process is being started asynchronously, early return. We'll end up |
| 537 // calling InitUserScripts when it's created which will call this again. | 407 // calling InitUserScripts when it's created which will call this again. |
| 538 base::ProcessHandle handle = process->GetHandle(); | 408 base::ProcessHandle handle = process->GetHandle(); |
| 539 if (!handle) | 409 if (!handle) |
| 540 return; | 410 return; |
| 541 | 411 |
| 542 base::SharedMemoryHandle handle_for_process; | 412 base::SharedMemoryHandle handle_for_process; |
| 543 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) | 413 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) |
| 544 return; // This can legitimately fail if the renderer asserts at startup. | 414 return; // This can legitimately fail if the renderer asserts at startup. |
| 545 | 415 |
| 546 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | 416 if (base::SharedMemory::IsHandleValid(handle_for_process)) { |
| 547 process->Send(new ExtensionMsg_UpdateUserScripts( | 417 process->Send(new ExtensionMsg_UpdateUserScripts( |
| 548 handle_for_process, "" /* owner */, changed_extensions)); | 418 handle_for_process, owner_extension_id_, changed_extensions)); |
| 549 } | 419 } |
| 550 } | 420 } |
| 551 | 421 |
| 552 } // namespace extensions | 422 } // namespace extensions |
| OLD | NEW |