Skip to content

Commit

Permalink
Enable <webview>.executeScript outside of Apps and Extensions [1]
Browse files Browse the repository at this point in the history
This patch enables javascript code injection like <webview>.executeScript({code: ...}), but does not include file injection like <webview>.executeScript({file: ...}). File injection will be in another patch.

BUG=434081

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

Cr-Commit-Position: refs/heads/master@{#319727}
  • Loading branch information
hanxi authored and Commit bot committed Mar 9, 2015
1 parent 7b41c65 commit 79f7a57
Show file tree
Hide file tree
Showing 18 changed files with 189 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "extensions/common/extension.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/extension_resource.h"
#include "extensions/common/host_id.h"
#include "media/audio/sounds/sounds_manager.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
#include "ui/base/resource/resource_bundle.h"
Expand Down Expand Up @@ -135,7 +136,7 @@ class ContentScriptLoader {
if (success) {
ExtensionMsg_ExecuteCode_Params params;
params.request_id = 0;
params.extension_id = extension_id_;
params.host_id = HostID(HostID::EXTENSIONS, extension_id_);
params.is_javascript = true;
params.code = data;
params.run_at = extensions::UserScript::DOCUMENT_IDLE;
Expand Down Expand Up @@ -204,7 +205,7 @@ void InjectChromeVoxContentScript(
// so that it won't interrupt our speech feedback enabled message.
ExtensionMsg_ExecuteCode_Params params;
params.request_id = 0;
params.extension_id = extension->id();
params.host_id = HostID(HostID::EXTENSIONS, extension->id());
params.is_javascript = true;
params.code = "window.INJECTED_AFTER_LOAD = true;";
params.run_at = extensions::UserScript::DOCUMENT_IDLE;
Expand Down
4 changes: 3 additions & 1 deletion chrome/browser/extensions/api/tabs/tabs_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/host_id.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/default_locale_handler.h"
#include "extensions/common/message_bundle.h"
Expand Down Expand Up @@ -1241,7 +1242,7 @@ bool TabsUpdateFunction::UpdateURL(const std::string &url_string,
}

TabHelper::FromWebContents(web_contents_)->script_executor()->ExecuteScript(
extension_id(),
HostID(HostID::EXTENSIONS, extension_id()),
ScriptExecutor::JAVASCRIPT,
url.GetContent(),
ScriptExecutor::TOP_FRAME,
Expand Down Expand Up @@ -1731,6 +1732,7 @@ bool ExecuteCodeInTabFunction::Init() {

execute_tab_id_ = tab_id;
details_ = details.Pass();
set_host_id(HostID(HostID::EXTENSIONS, extension()->id()));
return true;
}

Expand Down
46 changes: 46 additions & 0 deletions chrome/browser/ui/webui/webui_webview_browsertest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2015 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/macros.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/base/web_ui_browser_test.h"
#include "net/test/embedded_test_server/embedded_test_server.h"

class WebUIWebViewBrowserTest : public WebUIBrowserTest {
public:
WebUIWebViewBrowserTest() {}

void SetUpOnMainThread() override {
WebUIBrowserTest::SetUpOnMainThread();
AddLibrary(
base::FilePath(FILE_PATH_LITERAL("webview_execute_script_test.js")));

base::FilePath test_data_dir;
PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
}

GURL GetTestUrl(const std::string& path) const {
return embedded_test_server()->base_url().Resolve(path);
}

GURL GetWebViewEnabledWebUIURL() const {
return GURL(chrome::kChromeUIChromeSigninURL);
}

private:
DISALLOW_COPY_AND_ASSIGN(WebUIWebViewBrowserTest);
};

IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest, ExecuteScriptCode) {
ui_test_utils::NavigateToURL(browser(), GetWebViewEnabledWebUIURL());

ASSERT_TRUE(WebUIBrowserTest::RunJavascriptAsyncTest(
"testExecuteScriptCode",
new base::StringValue(GetTestUrl("empty.html").spec())));
}
1 change: 1 addition & 0 deletions chrome/chrome_tests.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@
'browser/ui/webui/signin/user_manager_ui_browsertest.cc',
'browser/ui/webui/web_ui_test_handler.cc',
'browser/ui/webui/web_ui_test_handler.h',
'browser/ui/webui/webui_webview_browsertest.cc',
'browser/ui/zoom/zoom_controller_browsertest.cc',
'browser/unload_browsertest.cc',
'common/mac/app_mode_chrome_locator_browsertest.mm',
Expand Down
32 changes: 32 additions & 0 deletions chrome/test/data/webui/webview_execute_script_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2015 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.

function createWebview() {
var webview = document.createElement('webview');
document.body.appendChild(webview);
return webview;
}

function testExecuteScriptCode(url) {
var webview = createWebview();

var onGetBackgroundExecuted = function(results) {
chrome.send('testResult', [results.length == 1 && results[0] == 'red']);
};

var onSetBackgroundExecuted = function() {
webview.executeScript({
code: 'document.body.style.backgroundColor;'
}, onGetBackgroundExecuted);
};

var onLoadStop = function() {
webview.executeScript({
code: 'document.body.style.backgroundColor = \'red\';'
}, onSetBackgroundExecuted);
};

webview.addEventListener('loadstop', onLoadStop);
webview.src = url;
}
8 changes: 6 additions & 2 deletions extensions/browser/api/execute_code_function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ bool ExecuteCodeFunction::Execute(const std::string& code_string) {
if (!executor)
return false;

if (!extension())
if (!extension() && !IsWebView())
return false;

ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT;
Expand Down Expand Up @@ -162,7 +162,7 @@ bool ExecuteCodeFunction::Execute(const std::string& code_string) {
CHECK_NE(UserScript::UNDEFINED, run_at);

executor->ExecuteScript(
extension()->id(),
host_id_,
script_type,
code_string,
frame_scope,
Expand Down Expand Up @@ -204,6 +204,10 @@ bool ExecuteCodeFunction::RunAsync() {

if (!details_->file.get())
return false;

if (!extension())
return false;

resource_ = extension()->GetResource(*details_->file);

if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
Expand Down
9 changes: 9 additions & 0 deletions extensions/browser/api/execute_code_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "extensions/browser/extension_function.h"
#include "extensions/browser/script_executor.h"
#include "extensions/common/api/extension_types.h"
#include "extensions/common/host_id.h"

namespace extensions {

Expand Down Expand Up @@ -39,6 +40,11 @@ class ExecuteCodeFunction : public AsyncExtensionFunction {
// The injection details.
scoped_ptr<core_api::extension_types::InjectDetails> details_;

const HostID& host_id() const { return host_id_; }
void set_host_id(HostID host_id) {
host_id_ = host_id;
}

private:
// Called when contents from the file whose path is specified in JSON
// arguments has been loaded.
Expand All @@ -65,6 +71,9 @@ class ExecuteCodeFunction : public AsyncExtensionFunction {

// The URL of the file being injected into the page.
GURL file_url_;

// The ID of the injection host.
HostID host_id_;
};

} // namespace extensions
Expand Down
14 changes: 13 additions & 1 deletion extensions/browser/api/web_view/web_view_internal_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,19 @@ bool WebViewInternalExecuteCodeFunction::Init() {
return false;

details_ = details.Pass();
return true;

if (extension()) {
set_host_id(HostID(HostID::EXTENSIONS, extension()->id()));
return true;
}

WebContents* web_contents = GetSenderWebContents();
if (web_contents && web_contents->GetWebUI()) {
const GURL& url = render_view_host()->GetSiteInstance()->GetSiteURL();
set_host_id(HostID(HostID::WEBUI, url.spec()));
return true;
}
return false;
}

bool WebViewInternalExecuteCodeFunction::ShouldInsertCSS() const {
Expand Down
29 changes: 17 additions & 12 deletions extensions/browser/script_executor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Handler : public content::WebContentsObserver {
const ScriptExecutor::ExecuteScriptCallback& callback)
: content::WebContentsObserver(web_contents),
script_observers_(AsWeakPtr(script_observers)),
extension_id_(params.extension_id),
host_id_(params.host_id),
request_id_(params.request_id),
callback_(callback) {
content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
Expand Down Expand Up @@ -78,9 +78,10 @@ class Handler : public content::WebContentsObserver {
const std::string& error,
const GURL& on_url,
const base::ListValue& script_result) {
if (script_observers_.get() && error.empty()) {
if (script_observers_.get() && error.empty() &&
host_id_.type() == HostID::EXTENSIONS) {
ScriptExecutionObserver::ExecutingScriptsMap id_map;
id_map[extension_id_] = std::set<std::string>();
id_map[host_id_.id()] = std::set<std::string>();
FOR_EACH_OBSERVER(ScriptExecutionObserver,
*script_observers_,
OnScriptsExecuted(web_contents(), id_map, on_url));
Expand All @@ -91,7 +92,7 @@ class Handler : public content::WebContentsObserver {
}

base::WeakPtr<ObserverList<ScriptExecutionObserver> > script_observers_;
std::string extension_id_;
HostID host_id_;
int request_id_;
ScriptExecutor::ExecuteScriptCallback callback_;
};
Expand All @@ -113,7 +114,7 @@ ScriptExecutor::ScriptExecutor(
ScriptExecutor::~ScriptExecutor() {
}

void ScriptExecutor::ExecuteScript(const std::string& extension_id,
void ScriptExecutor::ExecuteScript(const HostID& host_id,
ScriptExecutor::ScriptType script_type,
const std::string& code,
ScriptExecutor::FrameScope frame_scope,
Expand All @@ -126,16 +127,20 @@ void ScriptExecutor::ExecuteScript(const std::string& extension_id,
bool user_gesture,
ScriptExecutor::ResultType result_type,
const ExecuteScriptCallback& callback) {
// Don't execute if the extension has been unloaded.
const Extension* extension =
ExtensionRegistry::Get(web_contents_->GetBrowserContext())
->enabled_extensions().GetByID(extension_id);
if (!extension)
return;
if (host_id.type() == HostID::EXTENSIONS) {
// Don't execute if the extension has been unloaded.
const Extension* extension =
ExtensionRegistry::Get(web_contents_->GetBrowserContext())
->enabled_extensions().GetByID(host_id.id());
if (!extension)
return;
} else {
CHECK(process_type == WEB_VIEW_PROCESS);
}

ExtensionMsg_ExecuteCode_Params params;
params.request_id = next_request_id_++;
params.extension_id = extension_id;
params.host_id = host_id;
params.is_javascript = (script_type == JAVASCRIPT);
params.code = code;
params.all_frames = (frame_scope == ALL_FRAMES);
Expand Down
2 changes: 1 addition & 1 deletion extensions/browser/script_executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ScriptExecutor {
// |callback| will always be called even if the IPC'd renderer is destroyed
// before a response is received (in this case the callback will be with a
// failure and appropriate error message).
void ExecuteScript(const std::string& extension_id,
void ExecuteScript(const HostID& host_id,
ScriptType script_type,
const std::string& code,
FrameScope frame_scope,
Expand Down
24 changes: 24 additions & 0 deletions extensions/common/extension_messages.cc
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,30 @@ void ParamTraits<ManifestPermissionSet>::Log(
LogParam(p.map(), l);
}

void ParamTraits<HostID>::Write(
Message* m, const param_type& p) {
WriteParam(m, p.type());
WriteParam(m, p.id());
}

bool ParamTraits<HostID>::Read(
const Message* m, PickleIterator* iter, param_type* r) {
HostID::HostType type;
std::string id;
if (!ReadParam(m, iter, &type))
return false;
if (!ReadParam(m, iter, &id))
return false;
*r = HostID(type, id);
return true;
}

void ParamTraits<HostID>::Log(
const param_type& p, std::string* l) {
LogParam(p.type(), l);
LogParam(p.id(), l);
}

void ParamTraits<ExtensionMsg_PermissionSetStruct>::Write(Message* m,
const param_type& p) {
WriteParam(m, p.apis);
Expand Down
16 changes: 13 additions & 3 deletions extensions/common/extension_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "extensions/common/draggable_region.h"
#include "extensions/common/extension.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/host_id.h"
#include "extensions/common/permissions/media_galleries_permission_data.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/socket_permission_data.h"
Expand All @@ -38,6 +39,8 @@ IPC_ENUM_TRAITS_MAX_VALUE(content::SocketPermissionRequest::OperationType,
IPC_ENUM_TRAITS_MAX_VALUE(extensions::UserScript::InjectionType,
extensions::UserScript::INJECTION_TYPE_LAST)

IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)

// Parameters structure for ExtensionHostMsg_AddAPIActionToActivityLog and
// ExtensionHostMsg_AddEventToActivityLog.
IPC_STRUCT_BEGIN(ExtensionHostMsg_APIActionOrEvent_Params)
Expand Down Expand Up @@ -106,9 +109,8 @@ IPC_STRUCT_BEGIN(ExtensionMsg_ExecuteCode_Params)
// The extension API request id, for responding.
IPC_STRUCT_MEMBER(int, request_id)

// The ID of the requesting extension. To know which isolated world to
// execute the code inside of.
IPC_STRUCT_MEMBER(std::string, extension_id)
// The ID of the requesting injection host.
IPC_STRUCT_MEMBER(HostID, host_id)

// Whether the code is JavaScript or CSS.
IPC_STRUCT_MEMBER(bool, is_javascript)
Expand Down Expand Up @@ -337,6 +339,14 @@ struct ParamTraits<extensions::ManifestPermissionSet> {
static void Log(const param_type& p, std::string* l);
};

template <>
struct ParamTraits<HostID> {
typedef HostID param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, PickleIterator* iter, param_type* r);
static void Log(const param_type& p, std::string* l);
};

template <>
struct ParamTraits<ExtensionMsg_PermissionSetStruct> {
typedef ExtensionMsg_PermissionSetStruct param_type;
Expand Down
2 changes: 1 addition & 1 deletion extensions/common/host_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// IDs of hosts who own user scripts.
// A HostID is immutable after creation.
struct HostID {
enum HostType { EXTENSIONS, WEBUI };
enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };

HostID();
HostID(HostType type, const std::string& id);
Expand Down
5 changes: 3 additions & 2 deletions extensions/renderer/extension_injection_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ ExtensionInjectionHost::~ExtensionInjectionHost() {
}

// static
scoped_ptr<const ExtensionInjectionHost> ExtensionInjectionHost::Create(
const std::string& extension_id, const ExtensionSet* extensions) {
scoped_ptr<const InjectionHost> ExtensionInjectionHost::Create(
const std::string& extension_id,
const ExtensionSet* extensions) {
const Extension* extension = extensions->GetByID(extension_id);
if (!extension)
return scoped_ptr<const ExtensionInjectionHost>();
Expand Down
Loading

0 comments on commit 79f7a57

Please sign in to comment.