Chromium Code Reviews| Index: extensions/renderer/user_script_injection_list.cc |
| diff --git a/extensions/renderer/user_script_injection_list.cc b/extensions/renderer/user_script_injection_list.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b46dc78e818818cfd93d00e25f87128518125b2d |
| --- /dev/null |
| +++ b/extensions/renderer/user_script_injection_list.cc |
| @@ -0,0 +1,221 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "extensions/renderer/user_script_injection_list.h" |
| + |
| +#include "content/public/common/url_constants.h" |
| +#include "content/public/renderer/render_thread.h" |
| +#include "extensions/common/extension.h" |
| +#include "extensions/common/extension_messages.h" |
| +#include "extensions/common/extension_set.h" |
| +#include "extensions/common/permissions/permissions_data.h" |
| +#include "extensions/renderer/extensions_renderer_client.h" |
| +#include "extensions/renderer/script_context.h" |
| +#include "extensions/renderer/user_script_injection.h" |
| +#include "third_party/WebKit/public/web/WebDocument.h" |
| +#include "third_party/WebKit/public/web/WebFrame.h" |
| +#include "url/gurl.h" |
| + |
| +namespace extensions { |
| + |
| +// static |
| +GURL UserScriptInjectionList::GetDocumentUrlForFrame(blink::WebFrame* frame) { |
| + GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame); |
| + if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) { |
| + data_source_url = GURL(content::kViewSourceScheme + std::string(":") + |
| + data_source_url.spec()); |
| + } |
| + |
| + return data_source_url; |
| +} |
| + |
| +UserScriptInjectionList::UserScriptInjectionList() { |
| + content::RenderThread::Get()->AddObserver(this); |
| +} |
| + |
| +UserScriptInjectionList::~UserScriptInjectionList() { |
| +} |
| + |
| +void UserScriptInjectionList::AddObserver(Observer* observer) { |
| + observers_.AddObserver(observer); |
| +} |
| + |
| +void UserScriptInjectionList::RemoveObserver(Observer* observer) { |
| + observers_.RemoveObserver(observer); |
| +} |
| + |
| +void UserScriptInjectionList::GetActiveExtensionIds( |
| + std::set<std::string>* ids) const { |
| + for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin(); |
| + iter != scripts_.end(); |
| + ++iter) { |
| + DCHECK(!(*iter)->extension_id().empty()); |
| + ids->insert((*iter)->extension_id()); |
| + } |
| +} |
| + |
| +void UserScriptInjectionList::GetInjections( |
| + ScopedVector<ScriptInjection>* injections, |
| + blink::WebFrame* web_frame, |
| + int tab_id, |
| + UserScript::RunLocation run_location, |
| + const GURL& document_url, |
| + const ExtensionSet* extensions) { |
| + for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin(); |
| + iter != scripts_.end(); |
| + ++iter) { |
| + const Extension* extension = extensions->GetByID((*iter)->extension_id()); |
| + if (!extension) |
| + continue; |
| + scoped_ptr<ScriptInjection> injection = GetInjectionForScript( |
| + *iter, web_frame, tab_id, run_location, document_url, extension); |
| + if (injection.get()) |
| + injections->push_back(injection.release()); |
| + } |
| +} |
| + |
| +bool UserScriptInjectionList::OnControlMessageReceived( |
| + const IPC::Message& message) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(UserScriptInjectionList, message) |
| + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled; |
| +} |
| + |
| +void UserScriptInjectionList::OnUpdateUserScripts( |
| + base::SharedMemoryHandle shared_memory, |
| + const std::set<std::string>& changed_extensions) { |
| + if (!base::SharedMemory::IsHandleValid(shared_memory)) { |
| + NOTREACHED() << "Bad scripts handle"; |
| + return; |
| + } |
| + |
| + for (std::set<std::string>::const_iterator iter = changed_extensions.begin(); |
| + iter != changed_extensions.end(); |
| + ++iter) { |
| + if (!Extension::IdIsValid(*iter)) { |
| + NOTREACHED() << "Invalid extension id: " << *iter; |
| + return; |
| + } |
| + } |
| + |
| + if (UpdateScripts(shared_memory)) { |
| + FOR_EACH_OBSERVER(Observer, |
| + observers_, |
| + OnUserScriptsUpdated(changed_extensions, scripts_.get())); |
| + } |
| +} |
| + |
| +bool UserScriptInjectionList::UpdateScripts( |
| + base::SharedMemoryHandle shared_memory) { |
| + bool only_inject_incognito = |
| + ExtensionsRendererClient::Get()->IsIncognitoProcess(); |
| + |
| + // Create the shared memory object (read only). |
| + shared_memory_.reset(new base::SharedMemory(shared_memory, true)); |
| + if (!shared_memory_.get()) |
| + return false; |
| + |
| + // First get the size of the memory block. |
| + if (!shared_memory_->Map(sizeof(Pickle::Header))) |
| + return false; |
| + Pickle::Header* pickle_header = |
| + reinterpret_cast<Pickle::Header*>(shared_memory_->memory()); |
| + |
| + // Now map in the rest of the block. |
| + int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size; |
| + shared_memory_->Unmap(); |
| + if (!shared_memory_->Map(pickle_size)) |
| + return false; |
| + |
| + // Unpickle scripts. |
| + uint64 num_scripts = 0; |
| + Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size); |
| + PickleIterator iter(pickle); |
| + CHECK(pickle.ReadUInt64(&iter, &num_scripts)); |
| + |
| + scripts_.clear(); |
| + scripts_.reserve(num_scripts); |
| + for (uint64 i = 0; i < num_scripts; ++i) { |
| + scoped_ptr<UserScript> script(new UserScript()); |
| + script->Unpickle(pickle, &iter); |
| + |
| + // Note that this is a pointer into shared memory. We don't own it. It gets |
| + // cleared up when the last renderer or browser process drops their |
| + // reference to the shared memory. |
| + for (size_t j = 0; j < script->js_scripts().size(); ++j) { |
| + const char* body = NULL; |
| + int body_length = 0; |
| + CHECK(pickle.ReadData(&iter, &body, &body_length)); |
| + script->js_scripts()[j].set_external_content( |
| + base::StringPiece(body, body_length)); |
| + } |
| + for (size_t j = 0; j < script->css_scripts().size(); ++j) { |
| + const char* body = NULL; |
| + int body_length = 0; |
| + CHECK(pickle.ReadData(&iter, &body, &body_length)); |
| + script->css_scripts()[j].set_external_content( |
| + base::StringPiece(body, body_length)); |
| + } |
| + |
| + if (only_inject_incognito && !script->is_incognito_enabled()) |
| + continue; // This script shouldn't run in an incognito tab. |
| + |
| + scripts_.push_back(script.release()); |
| + } |
| + |
| + return true; |
| +} |
|
not at google - send to devlin
2014/06/15 23:53:38
blank line
Devlin
2014/06/16 18:11:17
Done.
|
| +scoped_ptr<ScriptInjection> UserScriptInjectionList::GetInjectionForScript( |
| + UserScript* script, |
| + blink::WebFrame* web_frame, |
| + int tab_id, |
| + UserScript::RunLocation run_location, |
| + const GURL& document_url, |
| + const Extension* extension) { |
| + scoped_ptr<ScriptInjection> injection; |
| + if (web_frame->parent() && !script->match_all_frames()) |
| + return injection.Pass(); // Only match subframes if the script declared it. |
| + |
| + // Content scripts are not tab-specific. |
| + static const int kNoTabId = -1; |
| + // We don't have a process id in this context. |
| + static const int kNoProcessId = -1; |
| + |
| + GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( |
| + web_frame, document_url, script->match_about_blank()); |
| + |
| + if (!script->MatchesURL(effective_document_url)) |
| + return injection.Pass(); |
| + |
| + if (!extension->permissions_data()->CanRunContentScriptOnPage( |
| + extension, |
| + effective_document_url, |
| + web_frame->top()->document().url(), |
| + kNoTabId, |
| + kNoProcessId, |
|
not at google - send to devlin
2014/06/15 23:53:38
inling -1 with those comments "Content scripts are
Devlin
2014/06/16 18:11:17
Done.
|
| + NULL /* ignore error */)) { |
| + return injection.Pass(); |
| + } |
| + |
| + bool inject_css = !script->css_scripts().empty() && |
| + run_location == UserScript::DOCUMENT_START; |
| + bool inject_js = |
| + !script->js_scripts().empty() && script->run_location() == run_location; |
|
not at google - send to devlin
2014/06/15 23:53:38
this mixing of UserScriptInjection getting its pro
Devlin
2014/06/16 18:11:17
Caching script id is done because when we need to
|
| + if (inject_css || inject_js) { |
| + injection.reset(new UserScriptInjection(web_frame, |
| + extension->id(), |
| + run_location, |
| + tab_id, |
| + this, |
| + script, |
| + inject_js, |
| + inject_css)); |
| + } |
| + return injection.Pass(); |
| +} |
| + |
| +} // namespace extensions |