16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/extensions/user_script_loader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/bind_helpers.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/memory/shared_memory.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/version.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/component_extension_resource_manager.h"
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/browser/content_verifier.h"
240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/browser/extension_registry.h"
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/browser/extension_system.h"
266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "extensions/common/extension_messages.h"
28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/file_util.h"
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/message_bundle.h"
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "extensions/common/one_shot_event.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)using extensions::ExtensionsBrowserClient;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)typedef base::Callback<
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    void(scoped_ptr<UserScriptList>, scoped_ptr<base::SharedMemory>)>
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    LoadScriptsCallback;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid VerifyContent(scoped_refptr<ContentVerifier> verifier,
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                   const ExtensionId& extension_id,
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   const base::FilePath& extension_root,
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   const base::FilePath& relative_path,
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   const std::string& content) {
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_refptr<ContentVerifyJob> job(
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      verifier->CreateJobFor(extension_id, extension_root, relative_path));
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (job.get()) {
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    job->Start();
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    job->BytesRead(content.size(), content.data());
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    job->DoneReading();
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool LoadScriptContent(const ExtensionId& extension_id,
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       UserScript::File* script_file,
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       const SubstitutionMap* localization_messages,
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       scoped_refptr<ContentVerifier> verifier) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string content;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath& path = ExtensionResource::GetFilePath(
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      script_file->extension_root(),
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      script_file->relative_path(),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionResource::SYMLINKS_MUST_RESOLVE_WITHIN_ROOT);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path.empty()) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int resource_id;
706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        IsComponentExtensionResource(script_file->extension_root(),
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                     script_file->relative_path(),
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                     &resource_id)) {
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content = rb.GetRawDataResource(resource_id).as_string();
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(WARNING) << "Failed to get file path to "
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   << script_file->relative_path().value() << " from "
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   << script_file->extension_root().value();
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!base::ReadFileToString(path, &content)) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(WARNING) << "Failed to load user script file: " << path.value();
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (verifier.get()) {
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      content::BrowserThread::PostTask(content::BrowserThread::IO,
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       FROM_HERE,
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       base::Bind(&VerifyContent,
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  verifier,
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  extension_id,
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  script_file->extension_root(),
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  script_file->relative_path(),
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  content));
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Localize the content.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (localization_messages) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string error;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MessageBundle::ReplaceMessagesWithExternalDictionary(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *localization_messages, &content, &error);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!error.empty()) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Failed to replace messages in script: " << error;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove BOM from the content.
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string::size_type index = content.find(base::kUtf8ByteOrderMark);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index == 0) {
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    script_file->set_content(content.substr(strlen(base::kUtf8ByteOrderMark)));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    script_file->set_content(content);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
120116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSubstitutionMap* GetLocalizationMessages(const ExtensionsInfo& extensions_info,
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                         const ExtensionId& extension_id) {
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ExtensionsInfo::const_iterator iter = extensions_info.find(extension_id);
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (iter == extensions_info.end())
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return NULL;
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return file_util::LoadMessageBundleSubstitutionMap(
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      iter->second.first, extension_id, iter->second.second);
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid LoadUserScripts(UserScriptList* user_scripts,
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     const ExtensionsInfo& extensions_info,
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                     const std::set<int>& added_script_ids,
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     ContentVerifier* verifier) {
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (UserScriptList::iterator script = user_scripts->begin();
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       script != user_scripts->end();
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++script) {
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (added_script_ids.count(script->id()) == 0)
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      continue;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<SubstitutionMap> localization_messages(
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        GetLocalizationMessages(extensions_info, script->extension_id()));
1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for (size_t k = 0; k < script->js_scripts().size(); ++k) {
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UserScript::File& script_file = script->js_scripts()[k];
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (script_file.GetContent().empty())
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        LoadScriptContent(script->extension_id(), &script_file, NULL, verifier);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for (size_t k = 0; k < script->css_scripts().size(); ++k) {
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      UserScript::File& script_file = script->css_scripts()[k];
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (script_file.GetContent().empty())
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        LoadScriptContent(script->extension_id(),
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                          &script_file,
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                          localization_messages.get(),
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          verifier);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Pickle user scripts and return pointer to the shared memory.
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdochscoped_ptr<base::SharedMemory> Serialize(const UserScriptList& scripts) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Pickle pickle;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pickle.WriteUInt64(scripts.size());
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (UserScriptList::const_iterator script = scripts.begin();
1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       script != scripts.end();
1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++script) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(aa): This can be replaced by sending content script metadata to
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // renderers along with other extension data in ExtensionMsg_Loaded.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See crbug.com/70516.
1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    script->Pickle(&pickle);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Write scripts as 'data' so that we can read it out in the slave without
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // allocating a new string.
1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for (size_t j = 0; j < script->js_scripts().size(); j++) {
1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::StringPiece contents = script->js_scripts()[j].GetContent();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pickle.WriteData(contents.data(), contents.length());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for (size_t j = 0; j < script->css_scripts().size(); j++) {
1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::StringPiece contents = script->css_scripts()[j].GetContent();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pickle.WriteData(contents.data(), contents.length());
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the shared memory object.
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::SharedMemory shared_memory;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::SharedMemoryCreateOptions options;
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  options.size = pickle.size();
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  options.share_read_only = true;
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!shared_memory.Create(options))
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return scoped_ptr<base::SharedMemory>();
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!shared_memory.Map(pickle.size()))
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return scoped_ptr<base::SharedMemory>();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy the pickle to shared memory.
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  memcpy(shared_memory.memory(), pickle.data(), pickle.size());
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::SharedMemoryHandle readonly_handle;
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(),
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                            &readonly_handle))
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return scoped_ptr<base::SharedMemory>();
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return make_scoped_ptr(new base::SharedMemory(readonly_handle,
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                /*read_only=*/true));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid LoadScriptsOnFileThread(scoped_ptr<UserScriptList> user_scripts,
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             const ExtensionsInfo& extensions_info,
20503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                             const std::set<int>& added_script_ids,
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             scoped_refptr<ContentVerifier> verifier,
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             LoadScriptsCallback callback) {
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(user_scripts.get());
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LoadUserScripts(
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      user_scripts.get(), extensions_info, added_script_ids, verifier.get());
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<base::SharedMemory> memory = Serialize(*user_scripts);
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BrowserThread::PostTask(
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BrowserThread::UI,
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::Bind(callback, base::Passed(&user_scripts), base::Passed(&memory)));
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Helper function to parse greasesmonkey headers
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool GetDeclarationValue(const base::StringPiece& line,
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         const base::StringPiece& prefix,
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                         std::string* value) {
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::StringPiece::size_type index = line.find(prefix);
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (index == base::StringPiece::npos)
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string temp(line.data() + index + prefix.length(),
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   line.length() - index - prefix.length());
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (temp.empty() || !IsWhitespace(temp[0]))
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static
2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                           UserScript* script) {
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // http://wiki.greasespot.net/Metadata_block
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::StringPiece line;
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t line_start = 0;
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t line_end = line_start;
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool in_metadata = false;
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kUserScriptBegin("// ==UserScript==");
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kUserScriptEng("// ==/UserScript==");
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kNamespaceDeclaration("// @namespace");
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kNameDeclaration("// @name");
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kVersionDeclaration("// @version");
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kDescriptionDeclaration("// @description");
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kIncludeDeclaration("// @include");
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kExcludeDeclaration("// @exclude");
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kMatchDeclaration("// @match");
256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kRunAtDeclaration("// @run-at");
258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kRunAtDocumentStartValue("document-start");
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kRunAtDocumentEndValue("document-end");
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (line_start < script_text.length()) {
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    line_end = script_text.find('\n', line_start);
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Handle the case where there is no trailing newline in the file.
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (line_end == std::string::npos)
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      line_end = script_text.length() - 1;
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    line.set(script_text.data() + line_start, line_end - line_start);
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!in_metadata) {
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (line.starts_with(kUserScriptBegin))
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        in_metadata = true;
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (line.starts_with(kUserScriptEng))
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        break;
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      std::string value;
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // We escape some characters that MatchPattern() considers special.
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->add_glob(value);
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->add_exclude_glob(value);
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->set_name_space(value);
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->set_name(value);
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        Version version(value);
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (version.IsValid())
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          script->set_version(version.GetString());
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->set_description(value);
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        URLPattern pattern(UserScript::ValidUserScriptSchemes());
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (URLPattern::PARSE_SUCCESS != pattern.Parse(value))
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return false;
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->add_url_pattern(pattern);
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        URLPattern exclude(UserScript::ValidUserScriptSchemes());
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (URLPattern::PARSE_SUCCESS != exclude.Parse(value))
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return false;
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        script->add_exclude_url_pattern(exclude);
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (value == kRunAtDocumentStartValue)
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          script->set_run_location(UserScript::DOCUMENT_START);
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        else if (value == kRunAtDocumentEndValue)
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          script->set_run_location(UserScript::DOCUMENT_END);
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        else if (value == kRunAtDocumentIdleValue)
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          script->set_run_location(UserScript::DOCUMENT_IDLE);
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        else
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return false;
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // TODO(aa): Handle more types of metadata.
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    line_start = line_end + 1;
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If no patterns were specified, default to @include *. This is what
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Greasemonkey does.
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (script->globs().empty() && script->url_patterns().is_empty())
328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    script->add_glob("*");
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static
3346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::LoadScriptsForTest(UserScriptList* user_scripts) {
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ExtensionsInfo info;
33603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::set<int> added_script_ids;
3376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (UserScriptList::iterator it = user_scripts->begin();
3386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != user_scripts->end();
3396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++it) {
3406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    added_script_ids.insert(it->id());
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LoadUserScripts(
3436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      user_scripts, info, added_script_ids, NULL /* no verifier for testing */);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UserScriptLoader::UserScriptLoader(Profile* profile,
3476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                   const ExtensionId& owner_extension_id,
3486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                   bool listen_for_extension_system_loaded)
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : user_scripts_(new UserScriptList()),
35003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      clear_scripts_(false),
3516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      extension_system_ready_(false),
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_load_(false),
3530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      profile_(profile),
3546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      owner_extension_id_(owner_extension_id),
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extension_registry_observer_(this),
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
3576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
3586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (listen_for_extension_system_loaded) {
3596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ExtensionSystem::Get(profile_)->ready().Post(
3606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FROM_HERE,
3616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        base::Bind(&UserScriptLoader::OnExtensionSystemReady,
3626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                   weak_factory_.GetWeakPtr()));
3636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
3646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    extension_system_ready_ = true;
3656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
3666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  registrar_.Add(this,
3676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::NotificationService::AllBrowserContextsAndSources());
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UserScriptLoader::~UserScriptLoader() {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts) {
3756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (std::set<UserScript>::const_iterator it = scripts.begin();
3766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != scripts.end();
3776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++it) {
3786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    removed_scripts_.erase(*it);
3796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    added_scripts_.insert(*it);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AttemptLoad();
382010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
383010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
3846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::RemoveScripts(const std::set<UserScript>& scripts) {
3856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (std::set<UserScript>::const_iterator it = scripts.begin();
3866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != scripts.end();
3876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++it) {
3886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    added_scripts_.erase(*it);
3896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    removed_scripts_.insert(*it);
3900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AttemptLoad();
3920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::ClearScripts() {
3956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  clear_scripts_ = true;
3966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  added_scripts_.clear();
3976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  removed_scripts_.clear();
3986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AttemptLoad();
3990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::Observe(int type,
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationSource& source,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationDetails& details) {
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED);
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  content::RenderProcessHost* process =
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      content::Source<content::RenderProcessHost>(source).ptr();
4076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext());
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!profile_->IsSameProfile(profile))
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
4106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (scripts_ready()) {
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SendUpdate(process,
4126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)               shared_memory_.get(),
4136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)               std::set<ExtensionId>());  // Include all extensions.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::OnExtensionUnloaded(
4186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    content::BrowserContext* browser_context,
4196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const Extension* extension,
4206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    UnloadedExtensionInfo::Reason reason) {
4216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  extensions_info_.erase(extension->id());
4226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::OnExtensionSystemReady() {
4256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  extension_system_ready_ = true;
4266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AttemptLoad();
4276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool UserScriptLoader::ScriptsMayHaveChanged() const {
4306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Scripts may have changed if there are scripts added, scripts removed, or
4316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // if scripts were cleared and either:
4326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // (1) A load is in progress (which may result in a non-zero number of
4336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  //     scripts that need to be cleared), or
4346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // (2) The current set of scripts is non-empty (so they need to be cleared).
4356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return (added_scripts_.size() ||
4366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          removed_scripts_.size() ||
4376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          (clear_scripts_ &&
4386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)           (is_loading() || user_scripts_->size())));
4396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::AttemptLoad() {
4426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (extension_system_ready_ && ScriptsMayHaveChanged()) {
4436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (is_loading())
4446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      pending_load_ = true;
4456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else
4466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      StartLoad();
4476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::StartLoad() {
451116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
452116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!is_loading());
453116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If scripts were marked for clearing before adding and removing, then clear
4556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // them.
4566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (clear_scripts_) {
4576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    user_scripts_->clear();
4586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
4596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for (UserScriptList::iterator it = user_scripts_->begin();
4606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)         it != user_scripts_->end();) {
4616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (removed_scripts_.count(*it))
4626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        it = user_scripts_->erase(it);
4636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      else
4646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        ++it;
465116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
466116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  user_scripts_->insert(
4696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      user_scripts_->end(), added_scripts_.begin(), added_scripts_.end());
4706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
47103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::set<int> added_script_ids;
4726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (std::set<UserScript>::const_iterator it = added_scripts_.begin();
4736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != added_scripts_.end();
4746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++it) {
4756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    added_script_ids.insert(it->id());
476116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
477116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Expand |changed_extensions_| for OnScriptsLoaded, which will use it in
4796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // its IPC message. This must be done before we clear |added_scripts_| and
4806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // |removed_scripts_| below.
4816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::set<UserScript> changed_scripts(added_scripts_);
4826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  changed_scripts.insert(removed_scripts_.begin(), removed_scripts_.end());
4836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ExpandChangedExtensions(changed_scripts);
4846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Update |extensions_info_| to contain info from every extension in
4866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // |changed_extensions_| before passing it to LoadScriptsOnFileThread.
4876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  UpdateExtensionsInfo();
4886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
489116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BrowserThread::PostTask(
490116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BrowserThread::FILE,
491116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FROM_HERE,
492116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&LoadScriptsOnFileThread,
493116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 base::Passed(&user_scripts_),
494116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 extensions_info_,
4956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 added_script_ids,
496116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 make_scoped_refptr(
497116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     ExtensionSystem::Get(profile_)->content_verifier()),
4986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 base::Bind(&UserScriptLoader::OnScriptsLoaded,
499116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            weak_factory_.GetWeakPtr())));
5006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  clear_scripts_ = false;
5026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  added_scripts_.clear();
5036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  removed_scripts_.clear();
504116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  user_scripts_.reset(NULL);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::OnScriptsLoaded(
5086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scoped_ptr<UserScriptList> user_scripts,
5096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    scoped_ptr<base::SharedMemory> shared_memory) {
5106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  user_scripts_.reset(user_scripts.release());
5116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (pending_load_) {
5126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // While we were loading, there were further changes. Don't bother
5136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // notifying about these scripts and instead just immediately reload.
5146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    pending_load_ = false;
5156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    StartLoad();
5166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
5176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
5186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (shared_memory.get() == NULL) {
5206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // This can happen if we run out of file descriptors.  In that case, we
5216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // have a choice between silently omitting all user scripts for new tabs,
5226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // by nulling out shared_memory_, or only silently omitting new ones by
5236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // leaving the existing object in place. The second seems less bad, even
5246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // though it removes the possibility that freeing the shared memory block
5256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // would open up enough FDs for long enough for a retry to succeed.
5266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Pretend the extension change didn't happen.
5286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
5296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
5306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // We've got scripts ready to go.
5326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  shared_memory_.reset(shared_memory.release());
5336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (content::RenderProcessHost::iterator i(
5356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)           content::RenderProcessHost::AllHostsIterator());
5366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       !i.IsAtEnd();
5376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       i.Advance()) {
5386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_extensions_);
5396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
5406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  changed_extensions_.clear();
5416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  content::NotificationService::current()->Notify(
5436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
5446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      content::Source<Profile>(profile_),
5456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      content::Details<base::SharedMemory>(shared_memory_.get()));
5466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
5476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::SendUpdate(
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::RenderProcessHost* process,
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::SharedMemory* shared_memory,
5516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::set<ExtensionId>& changed_extensions) {
552b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Don't allow injection of content scripts into <webview>.
553cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (process->IsIsolatedGuest())
554b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
555b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext());
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we only send user scripts to processes in our profile.
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile_->IsSameProfile(profile))
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the process is being started asynchronously, early return.  We'll end up
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // calling InitUserScripts when it's created which will call this again.
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ProcessHandle handle = process->GetHandle();
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handle)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SharedMemoryHandle handle_for_process;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!shared_memory->ShareToProcess(handle, &handle_for_process))
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // This can legitimately fail if the renderer asserts at startup.
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
571cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (base::SharedMemory::IsHandleValid(handle_for_process)) {
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    process->Send(new ExtensionMsg_UpdateUserScripts(
5731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        handle_for_process, owner_extension_id_, changed_extensions));
574cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::ExpandChangedExtensions(
5786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const std::set<UserScript>& scripts) {
5796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (std::set<UserScript>::const_iterator it = scripts.begin();
5806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != scripts.end();
5816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++it) {
5826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    changed_extensions_.insert(it->extension_id());
5836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
5846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
5856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UserScriptLoader::UpdateExtensionsInfo() {
5876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
5886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (std::set<ExtensionId>::const_iterator it = changed_extensions_.begin();
5896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != changed_extensions_.end();
5906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++it) {
5916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (extensions_info_.find(*it) == extensions_info_.end()) {
5926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      const Extension* extension =
5936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          registry->GetExtensionById(*it, ExtensionRegistry::EVERYTHING);
5946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // |changed_extensions_| may include extensions that have been removed,
5956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // which leads to the above lookup failing. In this case, just continue.
5966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (!extension)
5976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        continue;
5986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      extensions_info_[*it] = ExtensionSet::ExtensionPathAndDefaultLocale(
5996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          extension->path(), LocaleInfo::GetDefaultLocale(extension));
6006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
6016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
6026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
6036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
605