Commit 9ea140f4 authored by markdittmer's avatar markdittmer Committed by Commit bot

Renderer changes for wiring up shared memory with declarative injection

BUG=377978

Review URL: https://codereview.chromium.org/492133002

Cr-Commit-Position: refs/heads/master@{#292558}
parent b7e8c60b
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "chrome/browser/extensions/api/declarative/declarative_rule.h" #include "chrome/browser/extensions/api/declarative/declarative_rule.h"
#include "chrome/browser/extensions/declarative_user_script_master.h"
class Profile; class Profile;
...@@ -70,11 +71,97 @@ class ContentAction : public base::RefCounted<ContentAction> { ...@@ -70,11 +71,97 @@ class ContentAction : public base::RefCounted<ContentAction> {
std::string* error, std::string* error,
bool* bad_message); bool* bad_message);
// Shared procedure for resetting error state within factories.
static void ResetErrorData(std::string* error, bool* bad_message) {
*error = "";
*bad_message = false;
}
// Shared procedure for validating JSON data.
static bool Validate(const base::Value& json_action,
std::string* error,
bool* bad_message,
const base::DictionaryValue** action_dict,
std::string* instance_type);
protected: protected:
friend class base::RefCounted<ContentAction>; friend class base::RefCounted<ContentAction>;
virtual ~ContentAction(); virtual ~ContentAction();
}; };
// Action that injects a content script.
class RequestContentScript : public ContentAction {
public:
struct ScriptData {
ScriptData();
~ScriptData();
std::vector<std::string> css_file_names;
std::vector<std::string> js_file_names;
bool all_frames;
bool match_about_blank;
};
RequestContentScript(content::BrowserContext* browser_context,
const Extension* extension,
const ScriptData& script_data);
RequestContentScript(DeclarativeUserScriptMaster* master,
const Extension* extension,
const ScriptData& script_data);
static scoped_refptr<ContentAction> Create(
content::BrowserContext* browser_context,
const Extension* extension,
const base::DictionaryValue* dict,
std::string* error,
bool* bad_message);
static scoped_refptr<ContentAction> CreateForTest(
DeclarativeUserScriptMaster* master,
const Extension* extension,
const base::Value& json_action,
std::string* error,
bool* bad_message);
static bool InitScriptData(const base::DictionaryValue* dict,
std::string* error,
bool* bad_message,
ScriptData* script_data);
// Implementation of ContentAction:
virtual Type GetType() const OVERRIDE;
virtual void Apply(const std::string& extension_id,
const base::Time& extension_install_time,
ApplyInfo* apply_info) const OVERRIDE;
virtual void Reapply(const std::string& extension_id,
const base::Time& extension_install_time,
ApplyInfo* apply_info) const OVERRIDE;
virtual void Revert(const std::string& extension_id,
const base::Time& extension_install_time,
ApplyInfo* apply_info) const OVERRIDE;
private:
void InitScript(const Extension* extension, const ScriptData& script_data);
void AddScript() {
DCHECK(master_);
master_->AddScript(script_);
}
virtual ~RequestContentScript();
void InstructRenderProcessToInject(content::WebContents* contents,
const std::string& extension_id) const;
UserScript script_;
DeclarativeUserScriptMaster* master_;
DISALLOW_COPY_AND_ASSIGN(RequestContentScript);
};
typedef DeclarativeActionSet<ContentAction> ContentActionSet; typedef DeclarativeActionSet<ContentAction> ContentActionSet;
} // namespace extensions } // namespace extensions
......
// 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 "base/files/file_path.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/test_extension_dir.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
namespace {
// Manifest permissions injected into |kManifest|:
const char* kPermissions[] = {
"*://*/*", // ALL
"http://127.0.0.1/*", // PARTICULAR
"http://nowhere.com/*" // NOWHERE
};
// Script matchers for injected into |kBackgroundScriptSource|:
const char* kScriptMatchers[] = {
"{ pageUrl: { hostContains: '' } }", // ALL
"{ pageUrl: { hostEquals: '127.0.0.1' } }", // PARTICULAR
"{ pageUrl: { hostEquals: 'nowhere.com' } }" // NOWHERE
};
enum PermissionOrMatcherType {
ALL = 0,
PARTICULAR,
NOWHERE
};
// JSON/JS sources:
const char kManifest[] =
"{\n"
" \"name\": \"Test DeclarativeContentScript\",\n"
" \"manifest_version\": 2,\n"
" \"version\": \"1.0\",\n"
" \"description\": \"Test declarative content script interface\",\n"
" \"permissions\": [\"declarativeContent\", \"%s\"],\n"
" \"background\": {\n"
" \"scripts\": [\"background.js\"]\n"
" }\n"
"}\n";
const char kBackgroundScriptSource[] =
"var declarativeContent = chrome.declarativeContent;\n"
"var PageStateMatcher = declarativeContent.PageStateMatcher;\n"
"var RequestContentScript = declarativeContent.RequestContentScript;\n"
"var onPageChanged = declarativeContent.onPageChanged;\n"
"onPageChanged.removeRules(undefined, function() {\n"
" onPageChanged.addRules(\n"
" [{\n"
" conditions: [new PageStateMatcher(%s)],\n"
" actions: [new RequestContentScript({js: ['script.js']}\n"
" )]\n"
" }],\n"
" function(details) {\n"
" if (!chrome.runtime.lastError)\n"
" chrome.test.sendMessage('injection setup');\n"
" }\n"
" );\n"
"});\n";
const char kContentScriptSource[] =
"chrome.test.sendMessage('injection succeeded');\n";
// Messages from scripts:
const char kInjectionSetup[] = "injection setup";
const char kInjectionSucceeded[] = "injection succeeded";
// Runs all pending tasks in the renderer associated with |web_contents|.
// Returns true on success.
bool RunAllPendingInRenderer(content::WebContents* web_contents) {
// TODO(devlin): If too many tests start to need this, move it somewhere
// common.
// This is slight hack to achieve a RunPendingInRenderer() method. Since IPCs
// are sent synchronously, anything started prior to this method will finish
// before this method returns (as content::ExecuteScript() is synchronous).
return content::ExecuteScript(web_contents, "1 == 1;");
}
} // namespace
class RequestContentScriptAPITest : public ExtensionBrowserTest {
public:
RequestContentScriptAPITest();
virtual ~RequestContentScriptAPITest() {}
// Performs script injection test on a common local URL using the given
// |manifest_permission| and |script_matcher|. Does not return until
// the renderer should have completed its task and any browser-side reactions
// have been cleared from the task queue.
testing::AssertionResult RunTest(PermissionOrMatcherType manifest_permission,
PermissionOrMatcherType script_matcher,
bool should_inject);
private:
testing::AssertionResult CreateAndLoadExtension(
PermissionOrMatcherType manifest_permission,
PermissionOrMatcherType script_matcher);
scoped_ptr<TestExtensionDir> test_extension_dir_;
const Extension* extension_;
};
RequestContentScriptAPITest::RequestContentScriptAPITest()
: extension_(NULL) {}
testing::AssertionResult RequestContentScriptAPITest::RunTest(
PermissionOrMatcherType manifest_permission,
PermissionOrMatcherType script_matcher,
bool should_inject) {
if (extension_)
UnloadExtension(extension_->id());
testing::AssertionResult result = CreateAndLoadExtension(manifest_permission,
script_matcher);
if (!result)
return result;
// Setup listener for actual injection of script.
ExtensionTestMessageListener injection_succeeded_listener(
kInjectionSucceeded,
false /* won't reply */);
injection_succeeded_listener.set_extension_id(extension_->id());
ui_test_utils::NavigateToURL(
browser(),
embedded_test_server()->GetURL("/extensions/test_file.html"));
content::WebContents* web_contents =
browser() ? browser()->tab_strip_model()->GetActiveWebContents() : NULL;
if (!web_contents)
return testing::AssertionFailure() << "No web contents.";
// Give the extension plenty of time to inject.
if (!RunAllPendingInRenderer(web_contents))
return testing::AssertionFailure() << "Could not run pending in renderer.";
// Make sure all running tasks are complete.
content::RunAllPendingInMessageLoop();
if (injection_succeeded_listener.was_satisfied() != should_inject) {
return testing::AssertionFailure()
<< (should_inject ?
"Expected injection, but got none." :
"Expected no injection, but got one.");
}
return testing::AssertionSuccess();
}
testing::AssertionResult RequestContentScriptAPITest::CreateAndLoadExtension(
PermissionOrMatcherType manifest_permission,
PermissionOrMatcherType script_matcher) {
// Setup a listener to note when injection rules have been setup.
ExtensionTestMessageListener injection_setup_listener(
kInjectionSetup,
false /* won't reply */);
std::string manifest = base::StringPrintf(kManifest,
kPermissions[manifest_permission]);
std::string background_src = base::StringPrintf(
kBackgroundScriptSource,
kScriptMatchers[script_matcher]);
scoped_ptr<TestExtensionDir> dir(new TestExtensionDir);
dir->WriteManifest(manifest);
dir->WriteFile(FILE_PATH_LITERAL("background.js"), background_src);
dir->WriteFile(FILE_PATH_LITERAL("script.js"),
kContentScriptSource);
const Extension* extension = LoadExtension(dir->unpacked_path());
if (!extension)
return testing::AssertionFailure() << "Failed to load extension.";
test_extension_dir_.reset(dir.release());
extension_ = extension;
// Wait for rules to be setup before navigating to trigger script injection.
injection_setup_listener.WaitUntilSatisfied();
return testing::AssertionSuccess();
}
// Try different permutations of "match all", "match particular domain (that is
// visited by test)", and "match nonsense domain (not visited by test)" for
// both manifest permissions and injection matcher conditions.
IN_PROC_BROWSER_TEST_F(RequestContentScriptAPITest,
PermissionMatcherAgreementInjection) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
// Positive tests: permissions and matcher contain conditions that match URL
// visited during test.
EXPECT_TRUE(RunTest(ALL, ALL, true));
EXPECT_TRUE(RunTest(ALL, PARTICULAR, true));
EXPECT_TRUE(RunTest(PARTICULAR, ALL, true));
EXPECT_TRUE(RunTest(PARTICULAR, PARTICULAR, true));
// Negative tests: permissions or matcher (or both) contain conditions that
// do not match URL visited during test.
EXPECT_TRUE(RunTest(NOWHERE, ALL, false));
EXPECT_TRUE(RunTest(NOWHERE, PARTICULAR, false));
EXPECT_TRUE(RunTest(NOWHERE, NOWHERE, false));
EXPECT_TRUE(RunTest(ALL, NOWHERE, false));
EXPECT_TRUE(RunTest(PARTICULAR, NOWHERE, false));
// TODO(markdittmer): Add more tests:
// - Inject script with multiple files
// - Inject multiple scripts
// - Match on CSS selector conditions
// - Match all frames in document containing frames
}
} // namespace extensions
...@@ -1097,6 +1097,7 @@ ...@@ -1097,6 +1097,7 @@
'browser/extensions/api/debugger/debugger_extension_apitest.cc', 'browser/extensions/api/debugger/debugger_extension_apitest.cc',
'browser/extensions/api/declarative/declarative_apitest.cc', 'browser/extensions/api/declarative/declarative_apitest.cc',
'browser/extensions/api/declarative_content/declarative_content_apitest.cc', 'browser/extensions/api/declarative_content/declarative_content_apitest.cc',
'browser/extensions/api/declarative_content/request_content_script_apitest.cc',
'browser/extensions/api/desktop_capture/desktop_capture_apitest.cc', 'browser/extensions/api/desktop_capture/desktop_capture_apitest.cc',
'browser/extensions/api/developer_private/developer_private_apitest.cc', 'browser/extensions/api/developer_private/developer_private_apitest.cc',
'browser/extensions/api/dial/dial_apitest.cc', 'browser/extensions/api/dial/dial_apitest.cc',
......
...@@ -406,6 +406,13 @@ IPC_MESSAGE_CONTROL3(ExtensionMsg_UpdateUserScripts, ...@@ -406,6 +406,13 @@ IPC_MESSAGE_CONTROL3(ExtensionMsg_UpdateUserScripts,
extensions::ExtensionId /* owner */, extensions::ExtensionId /* owner */,
std::set<std::string> /* changed extensions */) std::set<std::string> /* changed extensions */)
// Trigger to execute declarative content script under browser control.
IPC_MESSAGE_ROUTED4(ExtensionMsg_ExecuteDeclarativeScript,
int /* tab identifier */,
extensions::ExtensionId /* extension identifier */,
int /* script identifier */,
GURL /* page URL where script should be injected */)
// Tell the render view which browser window it's being attached to. // Tell the render view which browser window it's being attached to.
IPC_MESSAGE_ROUTED1(ExtensionMsg_UpdateBrowserWindowId, IPC_MESSAGE_ROUTED1(ExtensionMsg_UpdateBrowserWindowId,
int /* id of browser window */) int /* id of browser window */)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "extensions/renderer/script_injection.h" #include "extensions/renderer/script_injection.h"
#include "extensions/renderer/scripts_run_info.h" #include "extensions/renderer/scripts_run_info.h"
#include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/public/web/WebView.h"
...@@ -48,6 +49,10 @@ class ScriptInjectionManager::RVOHelper : public content::RenderViewObserver { ...@@ -48,6 +49,10 @@ class ScriptInjectionManager::RVOHelper : public content::RenderViewObserver {
virtual void OnDestruct() OVERRIDE; virtual void OnDestruct() OVERRIDE;
virtual void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params); virtual void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params);
virtual void OnExecuteDeclarativeScript(int tab_id,
const ExtensionId& extension_id,
int script_id,
const GURL& url);
virtual void OnPermitScriptInjection(int64 request_id); virtual void OnPermitScriptInjection(int64 request_id);
// Tells the ScriptInjectionManager to run tasks associated with // Tells the ScriptInjectionManager to run tasks associated with
...@@ -87,6 +92,8 @@ bool ScriptInjectionManager::RVOHelper::OnMessageReceived( ...@@ -87,6 +92,8 @@ bool ScriptInjectionManager::RVOHelper::OnMessageReceived(
IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode) IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode)
IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection, IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection,
OnPermitScriptInjection) OnPermitScriptInjection)
IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteDeclarativeScript,
OnExecuteDeclarativeScript)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP() IPC_END_MESSAGE_MAP()
return handled; return handled;
...@@ -150,6 +157,26 @@ void ScriptInjectionManager::RVOHelper::OnExecuteCode( ...@@ -150,6 +157,26 @@ void ScriptInjectionManager::RVOHelper::OnExecuteCode(
manager_->HandleExecuteCode(params, render_view()); manager_->HandleExecuteCode(params, render_view());
} }
void ScriptInjectionManager::RVOHelper::OnExecuteDeclarativeScript(
int tab_id,
const ExtensionId& extension_id,
int script_id,
const GURL& url) {
blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
CHECK(main_frame);
// TODO(markdittmer): This would be cleaner if we compared page_ids instead.
// Begin script injeciton workflow only if the current URL is identical to
// the one that matched declarative conditions in the browser.
if (main_frame->top()->document().url() == url) {
manager_->HandleExecuteDeclarativeScript(main_frame,
tab_id,
extension_id,
script_id,
url);
}
}
void ScriptInjectionManager::RVOHelper::OnPermitScriptInjection( void ScriptInjectionManager::RVOHelper::OnPermitScriptInjection(
int64 request_id) { int64 request_id) {
manager_->HandlePermitScriptInjection(request_id); manager_->HandlePermitScriptInjection(request_id);
...@@ -323,6 +350,30 @@ void ScriptInjectionManager::HandleExecuteCode( ...@@ -323,6 +350,30 @@ void ScriptInjectionManager::HandleExecuteCode(
} }
} }
void ScriptInjectionManager::HandleExecuteDeclarativeScript(
blink::WebFrame* web_frame,
int tab_id,
const ExtensionId& extension_id,
int script_id,
const GURL& url) {
const Extension* extension = extensions_->GetByID(extension_id);
scoped_ptr<ScriptInjection> injection =
user_script_set_manager_->GetInjectionForDeclarativeScript(
script_id,
web_frame,
tab_id,
url,
extension);
if (injection.get()) {
ScriptsRunInfo scripts_run_info;
// TODO(markdittmer): Use return value of TryToInject for error handling.
injection->TryToInject(UserScript::BROWSER_DRIVEN,
extension,
&scripts_run_info);
scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN);
}
}
void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) {
ScopedVector<ScriptInjection>::iterator iter = ScopedVector<ScriptInjection>::iterator iter =
pending_injections_.begin(); pending_injections_.begin();
......
...@@ -72,6 +72,13 @@ class ScriptInjectionManager : public UserScriptSetManager::Observer { ...@@ -72,6 +72,13 @@ class ScriptInjectionManager : public UserScriptSetManager::Observer {
void HandleExecuteCode(const ExtensionMsg_ExecuteCode_Params& params, void HandleExecuteCode(const ExtensionMsg_ExecuteCode_Params& params,
content::RenderView* render_view); content::RenderView* render_view);
// Handle the ExecuteDeclarativeScript extension message.
void HandleExecuteDeclarativeScript(blink::WebFrame* web_frame,
int tab_id,
const ExtensionId& extension_id,
int script_id,
const GURL& url);
// Handle the GrantInjectionPermission extension message. // Handle the GrantInjectionPermission extension message.
void HandlePermitScriptInjection(int64 request_id); void HandlePermitScriptInjection(int64 request_id);
......
...@@ -56,10 +56,12 @@ base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api = ...@@ -56,10 +56,12 @@ base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api =
UserScriptInjector::UserScriptInjector( UserScriptInjector::UserScriptInjector(
const UserScript* script, const UserScript* script,
UserScriptSet* script_list) UserScriptSet* script_list,
bool is_declarative)
: script_(script), : script_(script),
script_id_(script_->id()), script_id_(script_->id()),
extension_id_(script_->extension_id()), extension_id_(script_->extension_id()),
is_declarative_(is_declarative),
user_script_set_observer_(this) { user_script_set_observer_(this) {
user_script_set_observer_.Add(script_list); user_script_set_observer_.Add(script_list);
} }
...@@ -132,13 +134,26 @@ PermissionsData::AccessType UserScriptInjector::CanExecuteOnFrame( ...@@ -132,13 +134,26 @@ PermissionsData::AccessType UserScriptInjector::CanExecuteOnFrame(
GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
web_frame, web_frame->document().url(), script_->match_about_blank()); web_frame, web_frame->document().url(), script_->match_about_blank());
return extension->permissions_data()->GetContentScriptAccess( // Declarative user scripts use "page access" (from "permissions" section in
extension, // manifest) whereas non-declarative user scripts use custom
effective_document_url, // "content script access" logic.
top_url, if (is_declarative_) {
tab_id, return extension->permissions_data()->GetPageAccess(
-1, // no process id extension,
NULL /* ignore error */); effective_document_url,
top_url,
tab_id,
-1, // no process id
NULL /* ignore error */);
} else {
return extension->permissions_data()->GetContentScriptAccess(
extension,
effective_document_url,
top_url,
tab_id,
-1, // no process id
NULL /* ignore error */);
}
} }
std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources( std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
......
...@@ -25,7 +25,8 @@ class UserScriptInjector : public ScriptInjector, ...@@ -25,7 +25,8 @@ class UserScriptInjector : public ScriptInjector,
public UserScriptSet::Observer { public UserScriptSet::Observer {
public: public:
UserScriptInjector(const UserScript* user_script, UserScriptInjector(const UserScript* user_script,
UserScriptSet* user_script_set); UserScriptSet* user_script_set,
bool is_declarative);
virtual ~UserScriptInjector(); virtual ~UserScriptInjector();
private: private:
...@@ -71,6 +72,10 @@ class UserScriptInjector : public ScriptInjector, ...@@ -71,6 +72,10 @@ class UserScriptInjector : public ScriptInjector,
// The associated extension id, preserved for the same reason as |script_id|. // The associated extension id, preserved for the same reason as |script_id|.
std::string extension_id_; std::string extension_id_;
// Indicates whether or not this script is declarative. This influences which
// script permissions are checked before injection.
bool is_declarative_;
ScopedObserver<UserScriptSet, UserScriptSet::Observer> ScopedObserver<UserScriptSet, UserScriptSet::Observer>
user_script_set_observer_; user_script_set_observer_;
......
...@@ -72,7 +72,13 @@ void UserScriptSet::GetInjections( ...@@ -72,7 +72,13 @@ void UserScriptSet::GetInjections(
if (!extension) if (!extension)
continue; continue;
scoped_ptr<ScriptInjection> injection = GetInjectionForScript( scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
*iter, web_frame, tab_id, run_location, document_url, extension); *iter,
web_frame,
tab_id,
run_location,
document_url,
extension,
false /* is_declarative */);
if (injection.get()) if (injection.get())
injections->push_back(injection.release()); injections->push_back(injection.release());
} }
...@@ -143,13 +149,37 @@ bool UserScriptSet::UpdateUserScripts( ...@@ -143,13 +149,37 @@ bool UserScriptSet::UpdateUserScripts(
return true; return true;
} }
scoped_ptr<ScriptInjection> UserScriptSet::GetDeclarativeScriptInjection(
int script_id,
blink::WebFrame* web_frame,
int tab_id,
UserScript::RunLocation run_location,
const GURL& document_url,
const Extension* extension) {
for (ScopedVector<UserScript>::const_iterator it = scripts_.begin();
it != scripts_.end();
++it) {
if ((*it)->id() == script_id) {
return GetInjectionForScript(*it,
web_frame,
tab_id,
run_location,
document_url,
extension,
true /* is_declarative */);
}
}
return scoped_ptr<ScriptInjection>();
}
scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript( scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
UserScript* script, UserScript* script,
blink::WebFrame* web_frame, blink::WebFrame* web_frame,
int tab_id, int tab_id,
UserScript::RunLocation run_location, UserScript::RunLocation run_location,
const GURL& document_url, const GURL& document_url,
const Extension* extension) { const Extension* extension,
bool is_declarative) {
scoped_ptr<ScriptInjection> injection; scoped_ptr<ScriptInjection> injection;
if (web_frame->parent() && !script->match_all_frames()) if (web_frame->parent() && !script->match_all_frames())
return injection.Pass(); // Only match subframes if the script declared it. return injection.Pass(); // Only match subframes if the script declared it.
...@@ -160,13 +190,15 @@ scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript( ...@@ -160,13 +190,15 @@ scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
if (!script->MatchesURL(effective_document_url)) if (!script->MatchesURL(effective_document_url))
return injection.Pass(); return injection.Pass();
if (extension->permissions_data()->GetContentScriptAccess( scoped_ptr<ScriptInjector> injector(new UserScriptInjector(script,
this,
is_declarative));
if (injector->CanExecuteOnFrame(
extension, extension,
effective_document_url, web_frame,
web_frame->top()->document().url(),
-1, // Content scripts are not tab-specific. -1, // Content scripts are not tab-specific.
-1, // We don't have a process id in this context. web_frame->top()->document().url()) ==
NULL /* ignore error */) == PermissionsData::ACCESS_DENIED) { PermissionsData::ACCESS_DENIED) {
return injection.Pass(); return injection.Pass();
} }
...@@ -176,7 +208,7 @@ scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript( ...@@ -176,7 +208,7 @@ scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
!script->js_scripts().empty() && script->run_location() == run_location; !script->js_scripts().empty() && script->run_location() == run_location;
if (inject_css || inject_js) { if (inject_css || inject_js) {
injection.reset(new ScriptInjection( injection.reset(new ScriptInjection(
scoped_ptr<ScriptInjector>(new UserScriptInjector(script, this)), injector.Pass(),
web_frame, web_frame,
extension->id(), extension->id(),
run_location, run_location,
......
...@@ -59,6 +59,14 @@ class UserScriptSet { ...@@ -59,6 +59,14 @@ class UserScriptSet {
int tab_id, int tab_id,
UserScript::RunLocation run_location); UserScript::RunLocation run_location);
scoped_ptr<ScriptInjection> GetDeclarativeScriptInjection(
int script_id,
blink::WebFrame* web_frame,
int tab_id,
UserScript::RunLocation run_location,
const GURL& document_url,
const Extension* extension);
// Updates scripts given the shared memory region containing user scripts. // Updates scripts given the shared memory region containing user scripts.
// Returns true if the scripts were successfully updated. // Returns true if the scripts were successfully updated.
bool UpdateUserScripts(base::SharedMemoryHandle shared_memory, bool UpdateUserScripts(base::SharedMemoryHandle shared_memory,
...@@ -75,7 +83,8 @@ class UserScriptSet { ...@@ -75,7 +83,8 @@ class UserScriptSet {
int tab_id, int tab_id,
UserScript::RunLocation run_location, UserScript::RunLocation run_location,
const GURL& document_url, const GURL& document_url,
const Extension* extension); const Extension* extension,
bool is_declarative);
// Shared memory containing raw script data. // Shared memory containing raw script data.
scoped_ptr<base::SharedMemory> shared_memory_; scoped_ptr<base::SharedMemory> shared_memory_;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_thread.h"
#include "extensions/common/extension_messages.h" #include "extensions/common/extension_messages.h"
#include "extensions/renderer/dispatcher.h" #include "extensions/renderer/dispatcher.h"
#include "extensions/renderer/script_injection.h"
#include "extensions/renderer/user_script_set.h" #include "extensions/renderer/user_script_set.h"
#include "ipc/ipc_message.h" #include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_macros.h"
...@@ -31,6 +32,27 @@ void UserScriptSetManager::RemoveObserver(Observer* observer) { ...@@ -31,6 +32,27 @@ void UserScriptSetManager::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer); observers_.RemoveObserver(observer);
} }
scoped_ptr<ScriptInjection>
UserScriptSetManager::GetInjectionForDeclarativeScript(
int script_id,
blink::WebFrame* web_frame,
int tab_id,
const GURL& url,
const Extension* extension) {
UserScriptSet* user_script_set =
GetProgrammaticScriptsByExtension(extension->id());
if (!user_script_set)
return scoped_ptr<ScriptInjection>();
return user_script_set->GetDeclarativeScriptInjection(
script_id,
web_frame,
tab_id,
UserScript::BROWSER_DRIVEN,
url,
extension);
}
bool UserScriptSetManager::OnControlMessageReceived( bool UserScriptSetManager::OnControlMessageReceived(
const IPC::Message& message) { const IPC::Message& message) {
bool handled = true; bool handled = true;
...@@ -41,13 +63,6 @@ bool UserScriptSetManager::OnControlMessageReceived( ...@@ -41,13 +63,6 @@ bool UserScriptSetManager::OnControlMessageReceived(
return handled; return handled;
} }
const UserScriptSet* UserScriptSetManager::GetProgrammaticScriptsByExtension(
const ExtensionId& extension_id) {
UserScriptSetMap::const_iterator it =
programmatic_scripts_.find(extension_id);
return it != programmatic_scripts_.end() ? it->second.get() : NULL;
}
void UserScriptSetManager::GetAllInjections( void UserScriptSetManager::GetAllInjections(
ScopedVector<ScriptInjection>* injections, ScopedVector<ScriptInjection>* injections,
blink::WebFrame* web_frame, blink::WebFrame* web_frame,
...@@ -72,6 +87,13 @@ void UserScriptSetManager::GetAllActiveExtensionIds( ...@@ -72,6 +87,13 @@ void UserScriptSetManager::GetAllActiveExtensionIds(
} }
} }
UserScriptSet* UserScriptSetManager::GetProgrammaticScriptsByExtension(
const ExtensionId& extension_id) {
UserScriptSetMap::const_iterator it =
programmatic_scripts_.find(extension_id);
return it != programmatic_scripts_.end() ? it->second.get() : NULL;
}
void UserScriptSetManager::OnUpdateUserScripts( void UserScriptSetManager::OnUpdateUserScripts(
base::SharedMemoryHandle shared_memory, base::SharedMemoryHandle shared_memory,
const ExtensionId& extension_id, const ExtensionId& extension_id,
...@@ -92,10 +114,10 @@ void UserScriptSetManager::OnUpdateUserScripts( ...@@ -92,10 +114,10 @@ void UserScriptSetManager::OnUpdateUserScripts(
UserScriptSet* scripts = NULL; UserScriptSet* scripts = NULL;
if (!extension_id.empty()) { if (!extension_id.empty()) {
// The expectation when there is an extensions that "owns" this shared // The expectation when there is an extension that "owns" this shared
// memory region is that it will list itself as the only changed extension. // memory region is that the |changed_extensions| is either the empty list
CHECK(changed_extensions.size() == 1 && // or just the owner.
changed_extensions.find(extension_id) != changed_extensions.end()); CHECK(changed_extensions.size() <= 1);
if (programmatic_scripts_.find(extension_id) == if (programmatic_scripts_.find(extension_id) ==
programmatic_scripts_.end()) { programmatic_scripts_.end()) {
scripts = new UserScriptSet(extensions_); scripts = new UserScriptSet(extensions_);
...@@ -114,7 +136,14 @@ void UserScriptSetManager::OnUpdateUserScripts( ...@@ -114,7 +136,14 @@ void UserScriptSetManager::OnUpdateUserScripts(
const std::set<std::string>* effective_extensions = &changed_extensions; const std::set<std::string>* effective_extensions = &changed_extensions;
std::set<std::string> all_extensions; std::set<std::string> all_extensions;
if (changed_extensions.empty()) { if (changed_extensions.empty()) {
all_extensions = extensions_->GetIDs(); // The meaning of "all extensions" varies, depending on whether some
// extension "owns" this shared memory region.
// No owner => all known extensions.
// Owner => just the owner extension.
if (extension_id.empty())
all_extensions = extensions_->GetIDs();
else
all_extensions.insert(extension_id);
effective_extensions = &all_extensions; effective_extensions = &all_extensions;
} }
......
...@@ -56,8 +56,14 @@ class UserScriptSetManager : public content::RenderProcessObserver { ...@@ -56,8 +56,14 @@ class UserScriptSetManager : public content::RenderProcessObserver {
void AddObserver(Observer* observer); void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer); void RemoveObserver(Observer* observer);
const UserScriptSet* GetProgrammaticScriptsByExtension( // Looks up the script injection associated with |script_id| and |extension|
const ExtensionId& extensionId); // in the context of the given |web_frame|, |tab_id|, and |url|.
scoped_ptr<ScriptInjection> GetInjectionForDeclarativeScript(
int script_id,
blink::WebFrame* web_frame,
int tab_id,
const GURL& url,
const Extension* extension);
// Put all injections from |static_scripts| and each of // Put all injections from |static_scripts| and each of
// |programmatic_scripts_| into |injections|. // |programmatic_scripts_| into |injections|.
...@@ -79,6 +85,9 @@ class UserScriptSetManager : public content::RenderProcessObserver { ...@@ -79,6 +85,9 @@ class UserScriptSetManager : public content::RenderProcessObserver {
// content::RenderProcessObserver implementation. // content::RenderProcessObserver implementation.
virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE; virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
UserScriptSet* GetProgrammaticScriptsByExtension(
const ExtensionId& extensionId);
// Handle the UpdateUserScripts extension message. // Handle the UpdateUserScripts extension message.
void OnUpdateUserScripts(base::SharedMemoryHandle shared_memory, void OnUpdateUserScripts(base::SharedMemoryHandle shared_memory,
const ExtensionId& extension_id, const ExtensionId& extension_id,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment