| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/user_script_loader.h" | 5 #include "extensions/browser/user_script_loader.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "extensions/common/extension_messages.h" | 22 #include "extensions/common/extension_messages.h" |
| 23 | 23 |
| 24 using content::BrowserThread; | 24 using content::BrowserThread; |
| 25 using content::BrowserContext; | 25 using content::BrowserContext; |
| 26 | 26 |
| 27 namespace extensions { | 27 namespace extensions { |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 #if DCHECK_IS_ON() | 31 #if DCHECK_IS_ON() |
| 32 bool AreScriptsUnique(const UserScriptList& scripts) { | 32 bool AreScriptsUnique(const BrowserUserScriptList& scripts) { |
| 33 std::set<int> script_ids; | 33 std::set<int> script_ids; |
| 34 for (const UserScript& script : scripts) { | 34 for (const std::unique_ptr<BrowserUserScript>& script : scripts) { |
| 35 if (script_ids.count(script.id())) | 35 if (script_ids.count(script->id())) |
| 36 return false; | 36 return false; |
| 37 script_ids.insert(script.id()); | 37 script_ids.insert(script->id()); |
| 38 } | 38 } |
| 39 return true; | 39 return true; |
| 40 } | 40 } |
| 41 #endif // DCHECK_IS_ON() | 41 #endif // DCHECK_IS_ON() |
| 42 | 42 |
| 43 // Helper function to parse greasesmonkey headers | 43 // Helper function to parse greasesmonkey headers |
| 44 bool GetDeclarationValue(const base::StringPiece& line, | 44 bool GetDeclarationValue(const base::StringPiece& line, |
| 45 const base::StringPiece& prefix, | 45 const base::StringPiece& prefix, |
| 46 std::string* value) { | 46 std::string* value) { |
| 47 base::StringPiece::size_type index = line.find(prefix); | 47 base::StringPiece::size_type index = line.find(prefix); |
| 48 if (index == base::StringPiece::npos) | 48 if (index == base::StringPiece::npos) |
| 49 return false; | 49 return false; |
| 50 | 50 |
| 51 std::string temp(line.data() + index + prefix.length(), | 51 std::string temp(line.data() + index + prefix.length(), |
| 52 line.length() - index - prefix.length()); | 52 line.length() - index - prefix.length()); |
| 53 | 53 |
| 54 if (temp.empty() || !base::IsUnicodeWhitespace(temp[0])) | 54 if (temp.empty() || !base::IsUnicodeWhitespace(temp[0])) |
| 55 return false; | 55 return false; |
| 56 | 56 |
| 57 base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value); | 57 base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value); |
| 58 return true; | 58 return true; |
| 59 } | 59 } |
| 60 | 60 |
| 61 } // namespace | 61 } // namespace |
| 62 | 62 |
| 63 // static | 63 // static |
| 64 bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text, | 64 bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text, |
| 65 UserScript* script) { | 65 BrowserUserScript* script) { |
| 66 // http://wiki.greasespot.net/Metadata_block | 66 // http://wiki.greasespot.net/Metadata_block |
| 67 base::StringPiece line; | 67 base::StringPiece line; |
| 68 size_t line_start = 0; | 68 size_t line_start = 0; |
| 69 size_t line_end = line_start; | 69 size_t line_end = line_start; |
| 70 bool in_metadata = false; | 70 bool in_metadata = false; |
| 71 | 71 |
| 72 static const base::StringPiece kUserScriptBegin("// ==UserScript=="); | 72 static const base::StringPiece kUserScriptBegin("// ==UserScript=="); |
| 73 static const base::StringPiece kUserScriptEng("// ==/UserScript=="); | 73 static const base::StringPiece kUserScriptEng("// ==/UserScript=="); |
| 74 static const base::StringPiece kNamespaceDeclaration("// @namespace"); | 74 static const base::StringPiece kNamespaceDeclaration("// @namespace"); |
| 75 static const base::StringPiece kNameDeclaration("// @name"); | 75 static const base::StringPiece kNameDeclaration("// @name"); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 // If no patterns were specified, default to @include *. This is what | 150 // If no patterns were specified, default to @include *. This is what |
| 151 // Greasemonkey does. | 151 // Greasemonkey does. |
| 152 if (script->globs().empty() && script->url_patterns().is_empty()) | 152 if (script->globs().empty() && script->url_patterns().is_empty()) |
| 153 script->add_glob("*"); | 153 script->add_glob("*"); |
| 154 | 154 |
| 155 return true; | 155 return true; |
| 156 } | 156 } |
| 157 | 157 |
| 158 UserScriptLoader::UserScriptLoader(BrowserContext* browser_context, | 158 UserScriptLoader::UserScriptLoader(BrowserContext* browser_context, |
| 159 const HostID& host_id) | 159 const HostID& host_id) |
| 160 : user_scripts_(new UserScriptList()), | 160 : user_scripts_(new BrowserUserScriptList()), |
| 161 clear_scripts_(false), | 161 clear_scripts_(false), |
| 162 ready_(false), | 162 ready_(false), |
| 163 pending_load_(false), | 163 pending_load_(false), |
| 164 browser_context_(browser_context), | 164 browser_context_(browser_context), |
| 165 host_id_(host_id), | 165 host_id_(host_id), |
| 166 weak_factory_(this) { | 166 weak_factory_(this) { |
| 167 registrar_.Add(this, | 167 registrar_.Add(this, |
| 168 content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 168 content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
| 169 content::NotificationService::AllBrowserContextsAndSources()); | 169 content::NotificationService::AllBrowserContextsAndSources()); |
| 170 } | 170 } |
| 171 | 171 |
| 172 UserScriptLoader::~UserScriptLoader() { | 172 UserScriptLoader::~UserScriptLoader() { |
| 173 FOR_EACH_OBSERVER(Observer, observers_, OnUserScriptLoaderDestroyed(this)); | 173 FOR_EACH_OBSERVER(Observer, observers_, OnUserScriptLoaderDestroyed(this)); |
| 174 } | 174 } |
| 175 | 175 |
| 176 void UserScriptLoader::AddScripts(const UserScriptList& scripts) { | 176 void UserScriptLoader::AddScripts(BrowserUserScriptList& scripts) { |
| 177 #if DCHECK_IS_ON() | 177 #if DCHECK_IS_ON() |
| 178 // |scripts| with non-unique IDs will work, but that would indicate we are | 178 // |scripts| with non-unique IDs will work, but that would indicate we are |
| 179 // doing something wrong somewhere, so DCHECK that. | 179 // doing something wrong somewhere, so DCHECK that. |
| 180 DCHECK(AreScriptsUnique(scripts)) | 180 DCHECK(AreScriptsUnique(scripts)) |
| 181 << "AddScripts() expects scripts with unique IDs."; | 181 << "AddScripts() expects scripts with unique IDs."; |
| 182 #endif // DCHECK_IS_ON() | 182 #endif // DCHECK_IS_ON() |
| 183 for (const UserScript& user_script : scripts) { | 183 for (std::unique_ptr<BrowserUserScript>& user_script : scripts) { |
| 184 int id = user_script.id(); | 184 int id = user_script->id(); |
| 185 removed_script_hosts_.erase(UserScriptIDPair(id)); | 185 removed_script_hosts_.erase(UserScriptIDPair(id)); |
| 186 if (added_scripts_map_.count(id) == 0) | 186 if (added_scripts_map_.count(id) == 0) |
| 187 added_scripts_map_[id] = user_script; | 187 added_scripts_map_[id] = std::move(user_script); |
| 188 } | 188 } |
| 189 AttemptLoad(); | 189 AttemptLoad(); |
| 190 } | 190 } |
| 191 | 191 |
| 192 void UserScriptLoader::AddScripts(const UserScriptList& scripts, | 192 void UserScriptLoader::AddScripts(BrowserUserScriptList& scripts, |
| 193 int render_process_id, | 193 int render_process_id, |
| 194 int render_view_id) { | 194 int render_view_id) { |
| 195 AddScripts(scripts); | 195 AddScripts(scripts); |
| 196 } | 196 } |
| 197 | 197 |
| 198 void UserScriptLoader::RemoveScripts( | 198 void UserScriptLoader::RemoveScripts( |
| 199 const std::set<UserScriptIDPair>& scripts) { | 199 const std::set<UserScriptIDPair>& scripts) { |
| 200 for (const UserScriptIDPair& id_pair : scripts) { | 200 for (const UserScriptIDPair& id_pair : scripts) { |
| 201 removed_script_hosts_.insert(UserScriptIDPair(id_pair.id, id_pair.host_id)); | 201 removed_script_hosts_.insert(UserScriptIDPair(id_pair.id, id_pair.host_id)); |
| 202 // TODO(lazyboy): We shouldn't be trying to remove scripts that were never | 202 // TODO(lazyboy): We shouldn't be trying to remove scripts that were never |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 | 251 |
| 252 void UserScriptLoader::StartLoad() { | 252 void UserScriptLoader::StartLoad() { |
| 253 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 253 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 254 DCHECK(!is_loading()); | 254 DCHECK(!is_loading()); |
| 255 | 255 |
| 256 // If scripts were marked for clearing before adding and removing, then clear | 256 // If scripts were marked for clearing before adding and removing, then clear |
| 257 // them. | 257 // them. |
| 258 if (clear_scripts_) { | 258 if (clear_scripts_) { |
| 259 user_scripts_->clear(); | 259 user_scripts_->clear(); |
| 260 } else { | 260 } else { |
| 261 for (UserScriptList::iterator it = user_scripts_->begin(); | 261 for (BrowserUserScriptList::iterator it = user_scripts_->begin(); |
| 262 it != user_scripts_->end();) { | 262 it != user_scripts_->end();) { |
| 263 UserScriptIDPair id_pair(it->id()); | 263 UserScriptIDPair id_pair(it->get()->id()); |
| 264 if (removed_script_hosts_.count(id_pair) > 0u) | 264 if (removed_script_hosts_.count(id_pair) > 0u) |
| 265 it = user_scripts_->erase(it); | 265 it = user_scripts_->erase(it); |
| 266 else | 266 else |
| 267 ++it; | 267 ++it; |
| 268 } | 268 } |
| 269 } | 269 } |
| 270 | 270 |
| 271 std::set<int> added_script_ids; | 271 std::set<int> added_script_ids; |
| 272 for (const auto& id_and_script : added_scripts_map_) | 272 for (const auto& id_and_script : added_scripts_map_) |
| 273 added_script_ids.insert(id_and_script.second.id()); | 273 added_script_ids.insert(id_and_script.second->id()); |
| 274 | 274 |
| 275 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in | 275 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in |
| 276 // its IPC message. This must be done before we clear |added_scripts_map_| and | 276 // its IPC message. This must be done before we clear |added_scripts_map_| and |
| 277 // |removed_script_hosts_| below. | 277 // |removed_script_hosts_| below. |
| 278 for (const auto& id_and_script : added_scripts_map_) | 278 for (const auto& id_and_script : added_scripts_map_) |
| 279 changed_hosts_.insert(id_and_script.second.host_id()); | 279 changed_hosts_.insert(id_and_script.second->host_id()); |
| 280 for (const UserScriptIDPair& id_pair : removed_script_hosts_) | 280 for (const UserScriptIDPair& id_pair : removed_script_hosts_) |
| 281 changed_hosts_.insert(id_pair.host_id); | 281 changed_hosts_.insert(id_pair.host_id); |
| 282 | 282 |
| 283 // Done with |added_scripts_map_|, now put them into |user_scripts_|. | 283 // Done with |added_scripts_map_|, now put them into |user_scripts_|. |
| 284 user_scripts_->reserve(user_scripts_->size() + added_scripts_map_.size()); | 284 user_scripts_->reserve(user_scripts_->size() + added_scripts_map_.size()); |
| 285 for (int id : added_script_ids) | 285 for (int id : added_script_ids) |
| 286 user_scripts_->push_back(std::move(added_scripts_map_[id])); | 286 user_scripts_->push_back(std::move(added_scripts_map_[id])); |
| 287 | 287 |
| 288 LoadScripts(std::move(user_scripts_), changed_hosts_, added_script_ids, | 288 LoadScripts(std::move(user_scripts_), changed_hosts_, added_script_ids, |
| 289 base::Bind(&UserScriptLoader::OnScriptsLoaded, | 289 base::Bind(&UserScriptLoader::OnScriptsLoaded, |
| 290 weak_factory_.GetWeakPtr())); | 290 weak_factory_.GetWeakPtr())); |
| 291 | 291 |
| 292 clear_scripts_ = false; | 292 clear_scripts_ = false; |
| 293 added_scripts_map_.clear(); | 293 added_scripts_map_.clear(); |
| 294 removed_script_hosts_.clear(); | 294 removed_script_hosts_.clear(); |
| 295 user_scripts_.reset(); | 295 user_scripts_.reset(); |
| 296 } | 296 } |
| 297 | 297 |
| 298 // static | 298 // static |
| 299 std::unique_ptr<base::SharedMemory> UserScriptLoader::Serialize( | 299 std::unique_ptr<base::SharedMemory> UserScriptLoader::Serialize( |
| 300 const UserScriptList& scripts) { | 300 const BrowserUserScriptList& scripts) { |
| 301 base::Pickle pickle; | 301 base::Pickle pickle; |
| 302 pickle.WriteUInt32(scripts.size()); | 302 pickle.WriteUInt32(scripts.size()); |
| 303 for (const UserScript& script : scripts) { | 303 for (const std::unique_ptr<BrowserUserScript>& script : scripts) { |
| 304 // TODO(aa): This can be replaced by sending content script metadata to | 304 // TODO(aa): This can be replaced by sending content script metadata to |
| 305 // renderers along with other extension data in ExtensionMsg_Loaded. | 305 // renderers along with other extension data in ExtensionMsg_Loaded. |
| 306 // See crbug.com/70516. | 306 // See crbug.com/70516. |
| 307 script.Pickle(&pickle); | 307 script->Pickle(&pickle); |
| 308 // Write scripts as 'data' so that we can read it out in the slave without | 308 // Write scripts as 'data' so that we can read it out in the slave without |
| 309 // allocating a new string. | 309 // allocating a new string. |
| 310 for (const UserScript::File& script_file : script.js_scripts()) { | 310 for (const std::unique_ptr<BrowserScriptFile>& script_file : |
| 311 base::StringPiece contents = script_file.GetContent(); | 311 script->js_scripts()) { |
| 312 base::StringPiece contents = script_file->GetContent(); |
| 312 pickle.WriteData(contents.data(), contents.length()); | 313 pickle.WriteData(contents.data(), contents.length()); |
| 313 } | 314 } |
| 314 for (const UserScript::File& script_file : script.css_scripts()) { | 315 for (const std::unique_ptr<BrowserScriptFile>& script_file : |
| 315 base::StringPiece contents = script_file.GetContent(); | 316 script->css_scripts()) { |
| 317 base::StringPiece contents = script_file->GetContent(); |
| 316 pickle.WriteData(contents.data(), contents.length()); | 318 pickle.WriteData(contents.data(), contents.length()); |
| 317 } | 319 } |
| 318 } | 320 } |
| 319 | 321 |
| 320 // Create the shared memory object. | 322 // Create the shared memory object. |
| 321 base::SharedMemory shared_memory; | 323 base::SharedMemory shared_memory; |
| 322 | 324 |
| 323 base::SharedMemoryCreateOptions options; | 325 base::SharedMemoryCreateOptions options; |
| 324 options.size = pickle.size(); | 326 options.size = pickle.size(); |
| 325 options.share_read_only = true; | 327 options.share_read_only = true; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 350 } | 352 } |
| 351 | 353 |
| 352 void UserScriptLoader::SetReady(bool ready) { | 354 void UserScriptLoader::SetReady(bool ready) { |
| 353 bool was_ready = ready_; | 355 bool was_ready = ready_; |
| 354 ready_ = ready; | 356 ready_ = ready; |
| 355 if (ready_ && !was_ready) | 357 if (ready_ && !was_ready) |
| 356 AttemptLoad(); | 358 AttemptLoad(); |
| 357 } | 359 } |
| 358 | 360 |
| 359 void UserScriptLoader::OnScriptsLoaded( | 361 void UserScriptLoader::OnScriptsLoaded( |
| 360 std::unique_ptr<UserScriptList> user_scripts, | 362 std::unique_ptr<BrowserUserScriptList> user_scripts, |
| 361 std::unique_ptr<base::SharedMemory> shared_memory) { | 363 std::unique_ptr<base::SharedMemory> shared_memory) { |
| 362 user_scripts_.reset(user_scripts.release()); | 364 user_scripts_.reset(user_scripts.release()); |
| 363 if (pending_load_) { | 365 if (pending_load_) { |
| 364 // While we were loading, there were further changes. Don't bother | 366 // While we were loading, there were further changes. Don't bother |
| 365 // notifying about these scripts and instead just immediately reload. | 367 // notifying about these scripts and instead just immediately reload. |
| 366 pending_load_ = false; | 368 pending_load_ = false; |
| 367 StartLoad(); | 369 StartLoad(); |
| 368 return; | 370 return; |
| 369 } | 371 } |
| 370 | 372 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) | 422 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) |
| 421 return; // This can legitimately fail if the renderer asserts at startup. | 423 return; // This can legitimately fail if the renderer asserts at startup. |
| 422 | 424 |
| 423 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | 425 if (base::SharedMemory::IsHandleValid(handle_for_process)) { |
| 424 process->Send(new ExtensionMsg_UpdateUserScripts( | 426 process->Send(new ExtensionMsg_UpdateUserScripts( |
| 425 handle_for_process, host_id(), changed_hosts, whitelisted_only)); | 427 handle_for_process, host_id(), changed_hosts, whitelisted_only)); |
| 426 } | 428 } |
| 427 } | 429 } |
| 428 | 430 |
| 429 } // namespace extensions | 431 } // namespace extensions |
| OLD | NEW |