diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 01:52:56 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 01:52:56 +0000 |
commit | 146486ff9a39e4d323df0e60e891e33a1e8d8390 (patch) | |
tree | f61da72a65c5c94807b639a6c88b7d8b4369dfb2 | |
parent | a74efa3f82f1ce5ed2d61cfc1ac22410355eb32f (diff) | |
download | chromium_src-146486ff9a39e4d323df0e60e891e33a1e8d8390.zip chromium_src-146486ff9a39e4d323df0e60e891e33a1e8d8390.tar.gz chromium_src-146486ff9a39e4d323df0e60e891e33a1e8d8390.tar.bz2 |
Make all content scripts from an extension run in the same
isolated world. Chromium side of change.
Review URL: http://codereview.chromium.org/262002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28369 0039d316-1c4b-4281-b951-d872f2087c98
18 files changed, 138 insertions, 17 deletions
@@ -1,7 +1,7 @@ vars = { "webkit_trunk": "http://svn.webkit.org/repository/webkit/trunk", - "webkit_revision": "49260", + "webkit_revision": "49278", "ffmpeg_revision": "27457", } diff --git a/chrome/browser/extensions/isolated_world_apitest.cc b/chrome/browser/extensions/isolated_world_apitest.cc new file mode 100644 index 0000000..25c6144 --- /dev/null +++ b/chrome/browser/extensions/isolated_world_apitest.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2009 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 "chrome/browser/extensions/extension_apitest.h" + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IsolatedWorld1) { + // This extension runs various bits of script and tests that they all run in + // the same isolated world. + StartHTTPServer(); + ASSERT_TRUE(RunExtensionTest("isolated_world1")) << message_; + + // Now load a different extension, inject into same page, verify worlds aren't + // shared. + ASSERT_TRUE(RunExtensionTest("isolated_world2")) << message_; +} diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 0aef38a..780dc7d 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -62,6 +62,7 @@ 'browser/extensions/extension_browsertests_misc.cc', 'browser/extensions/extension_override_apitest.cc', 'browser/extensions/extension_toolstrip_apitest.cc', + 'browser/extensions/isolated_world_apitest.cc' ], 'browser_tests_sources_win_specific': [ 'browser/extensions/browser_action_test.cc', @@ -95,6 +96,7 @@ 'browser/extensions/extension_browsertests_misc.cc', 'browser/extensions/extension_override_apitest.cc', 'browser/extensions/extension_toolstrip_apitest.cc', + 'browser/extensions/isolated_world_apitest.cc', 'browser/ssl/ssl_browser_tests.cc', ], # TODO(jcampan): move these vars to views.gyp. diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index ae98ac3..7c626ad 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -3606,8 +3606,9 @@ void RenderView::OnExecuteCode(int request_id, const std::string& extension_id, sources.push_back( WebScriptSource(WebString::fromUTF8(code_string))); UserScriptSlave::InsertInitExtensionCode(&sources, extension_id); - main_frame->executeScriptInNewWorld(&sources.front(), sources.size(), - EXTENSION_GROUP_CONTENT_SCRIPTS); + main_frame->executeScriptInIsolatedWorld( + UserScriptSlave::GetIsolatedWorldId(extension_id), + &sources.front(), sources.size(), EXTENSION_GROUP_CONTENT_SCRIPTS); } else { main_frame->insertStyleText(WebString::fromUTF8(code_string), WebString()); } diff --git a/chrome/renderer/user_script_slave.cc b/chrome/renderer/user_script_slave.cc index f76a1e7..86fcc1a 100644 --- a/chrome/renderer/user_script_slave.cc +++ b/chrome/renderer/user_script_slave.cc @@ -32,6 +32,25 @@ static const char kInitExtension[] = "chrome.extension = new chrome.Extension('%s');" "chrome.self.onConnect = chrome.extension.onConnect;"; +int UserScriptSlave::GetIsolatedWorldId(const std::string& extension_id) { + typedef std::map<std::string, int> IsolatedWorldMap; + + static IsolatedWorldMap g_isolated_world_ids; + static int g_next_isolated_world_id = 1; + + IsolatedWorldMap::iterator iter = g_isolated_world_ids.find(extension_id); + if (iter != g_isolated_world_ids.end()) + return iter->second; + + int new_id = g_next_isolated_world_id; + ++g_next_isolated_world_id; + + // This map will tend to pile up over time, but realistically, you're never + // going to have enough extensions for it to matter. + g_isolated_world_ids[extension_id] = new_id; + return new_id; +} + UserScriptSlave::UserScriptSlave() : shared_memory_(NULL), script_deleter_(&scripts_), @@ -159,6 +178,8 @@ bool UserScriptSlave::InjectScripts(WebFrame* frame, } if (!sources.empty()) { + int isolated_world_id = 0; + if (script->is_standalone()) { // For standalone scripts, we try to emulate the Greasemonkey API. sources.insert(sources.begin(), @@ -167,10 +188,12 @@ bool UserScriptSlave::InjectScripts(WebFrame* frame, // Setup chrome.self to contain an Extension object with the correct // ID. InsertInitExtensionCode(&sources, script->extension_id()); + isolated_world_id = GetIsolatedWorldId(script->extension_id()); } - frame->executeScriptInNewWorld(&sources.front(), sources.size(), - EXTENSION_GROUP_CONTENT_SCRIPTS); + frame->executeScriptInIsolatedWorld( + isolated_world_id, &sources.front(), sources.size(), + EXTENSION_GROUP_CONTENT_SCRIPTS); } } diff --git a/chrome/renderer/user_script_slave.h b/chrome/renderer/user_script_slave.h index 39407f1..8232ec4 100644 --- a/chrome/renderer/user_script_slave.h +++ b/chrome/renderer/user_script_slave.h @@ -35,6 +35,8 @@ class UserScriptSlave { // testability. bool InjectScripts(WebKit::WebFrame* frame, UserScript::RunLocation location); + static int GetIsolatedWorldId(const std::string& extension_id); + static void InsertInitExtensionCode(std::vector<WebScriptSource>* sources, const std::string& extension_id); private: diff --git a/chrome/test/data/extensions/api_test/isolated_world1/a.js b/chrome/test/data/extensions/api_test/isolated_world1/a.js new file mode 100644 index 0000000..95eacea --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world1/a.js @@ -0,0 +1,2 @@ +// This variable is read and updated by other script from the extenion. +var num = 1; diff --git a/chrome/test/data/extensions/api_test/isolated_world1/b.js b/chrome/test/data/extensions/api_test/isolated_world1/b.js new file mode 100644 index 0000000..5e66b40 --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world1/b.js @@ -0,0 +1,2 @@ +// Updates the variable defined in a.js. +num++; diff --git a/chrome/test/data/extensions/api_test/isolated_world1/background.html b/chrome/test/data/extensions/api_test/isolated_world1/background.html new file mode 100644 index 0000000..d5125c4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world1/background.html @@ -0,0 +1,23 @@ +<script> +chrome.extension.onConnect.addListener(function(port) { + chrome.test.log("got connect"); + port.onMessage.addListener(function(msg) { + chrome.test.log("got message: " + msg); + chrome.test.assertEq(2, msg); + chrome.test.notifyPass(); + }); +}); + +chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) { + chrome.test.log("Got update event: " + JSON.stringify(changeInfo)); + if (changeInfo.status == "complete") { + chrome.tabs.executeScript(tabId, {file: "c.js"}); + chrome.tabs.onUpdated.removeListener(arguments.callee); + } +}); + +chrome.test.log("Creating tab..."); +chrome.tabs.create({ + url: "http://localhost:1337/files/extensions/test_file.html" +}); +</script> diff --git a/chrome/test/data/extensions/api_test/isolated_world1/c.js b/chrome/test/data/extensions/api_test/isolated_world1/c.js new file mode 100644 index 0000000..d3bbc41 --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world1/c.js @@ -0,0 +1,2 @@ +// Send the variable defined by a.js and modified by b.js back to the extension. +chrome.extension.connect().postMessage(num); diff --git a/chrome/test/data/extensions/api_test/isolated_world1/manifest.json b/chrome/test/data/extensions/api_test/isolated_world1/manifest.json new file mode 100644 index 0000000..0528cdd --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world1/manifest.json @@ -0,0 +1,17 @@ +{
+ "name": "isolated world 1",
+ "version": "0.1",
+ "description": "tests that all scripts from an extension run in the same isolated world",
+ "background_page": "background.html",
+ "permissions": ["http://*/*", "tabs"],
+ "content_scripts": [
+ {
+ "matches": ["http://*/*"],
+ "js": ["a.js"]
+ },
+ {
+ "matches": ["http://*/*"],
+ "js": ["b.js"]
+ }
+ ]
+}
diff --git a/chrome/test/data/extensions/api_test/isolated_world2/a.js b/chrome/test/data/extensions/api_test/isolated_world2/a.js new file mode 100644 index 0000000..394feee --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world2/a.js @@ -0,0 +1,3 @@ +// We should not be able to read the "num" variable which was defined in a.js +// from the "isolated world 1" extension. +chrome.extension.connect().postMessage(typeof num == "undefined"); diff --git a/chrome/test/data/extensions/api_test/isolated_world2/background.html b/chrome/test/data/extensions/api_test/isolated_world2/background.html new file mode 100644 index 0000000..731182f --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world2/background.html @@ -0,0 +1,18 @@ +<script> +chrome.extension.onConnect.addListener(function(port) { + chrome.test.log("got connect"); + port.onMessage.addListener(function(msg) { + chrome.test.log("got message: " + msg); + chrome.test.assertTrue(msg); + chrome.test.notifyPass(); + }); +}); + +chrome.tabs.getAllInWindow(null, function(tabs) { + chrome.test.log("Got tabs: " + JSON.stringify(tabs)); + + // The last tab is the one that the other extension should have run scripts + // in. + chrome.tabs.executeScript(tabs.pop().id, {file: "a.js"}); +}); +</script> diff --git a/chrome/test/data/extensions/api_test/isolated_world2/manifest.json b/chrome/test/data/extensions/api_test/isolated_world2/manifest.json new file mode 100644 index 0000000..c4c60b5 --- /dev/null +++ b/chrome/test/data/extensions/api_test/isolated_world2/manifest.json @@ -0,0 +1,7 @@ +{
+ "name": "isolated world 2",
+ "version": "0.1",
+ "description": "together with isolated world 1, tests that scripts from different extensions run in different worlds",
+ "background_page": "background.html",
+ "permissions": ["http://*/*", "tabs"]
+}
diff --git a/webkit/api/public/WebFrame.h b/webkit/api/public/WebFrame.h index 07f5cf5..671c550 100644 --- a/webkit/api/public/WebFrame.h +++ b/webkit/api/public/WebFrame.h @@ -196,9 +196,9 @@ namespace WebKit { // extensionGroup is an embedder-provided specifier that controls which // v8 extensions are loaded into the new context - see // WebKit::registerExtension for the corresponding specifier. - virtual void executeScriptInNewWorld(const WebScriptSource* sources, - unsigned numSources, - int extensionGroup) = 0; + virtual void executeScriptInIsolatedWorld( + int worldId, const WebScriptSource* sources, unsigned numSources, + int extensionGroup) = 0; // Logs to the console associated with this frame. virtual void addMessageToConsole(const WebConsoleMessage&) = 0; diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc index 7fd7ce9..511a238 100644 --- a/webkit/glue/webframe_impl.cc +++ b/webkit/glue/webframe_impl.cc @@ -628,8 +628,8 @@ void WebFrameImpl::executeScriptInNewContext( frame_->script()->evaluateInNewContext(sources, extension_group); } -void WebFrameImpl::executeScriptInNewWorld( - const WebScriptSource* sources_in, unsigned num_sources, +void WebFrameImpl::executeScriptInIsolatedWorld( + int world_id, const WebScriptSource* sources_in, unsigned num_sources, int extension_group) { Vector<WebCore::ScriptSourceCode> sources; @@ -640,7 +640,7 @@ void WebFrameImpl::executeScriptInNewWorld( sources_in[i].startLine)); } - frame_->script()->evaluateInNewWorld(sources, extension_group); + frame_->script()->evaluateInIsolatedWorld(world_id, sources, extension_group); } void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) { diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h index b4cff81..f840df4 100644 --- a/webkit/glue/webframe_impl.h +++ b/webkit/glue/webframe_impl.h @@ -99,9 +99,9 @@ class WebFrameImpl : public WebKit::WebFrame, public RefCounted<WebFrameImpl> { virtual void executeScriptInNewContext( const WebKit::WebScriptSource* sources, unsigned num_sources, int extension_group); - virtual void executeScriptInNewWorld( - const WebKit::WebScriptSource* sources, unsigned num_sources, - int extension_group); + virtual void executeScriptInIsolatedWorld( + int world_id, const WebKit::WebScriptSource* sources, + unsigned num_sources, int extension_group); virtual void addMessageToConsole(const WebKit::WebConsoleMessage&); virtual void collectGarbage(); #if WEBKIT_USING_V8 diff --git a/webkit/tools/test_shell/layout_test_controller.cc b/webkit/tools/test_shell/layout_test_controller.cc index 3dd2be2..d757d8b 100644 --- a/webkit/tools/test_shell/layout_test_controller.cc +++ b/webkit/tools/test_shell/layout_test_controller.cc @@ -825,9 +825,12 @@ void LayoutTestController::setXSSAuditorEnabled( void LayoutTestController::evaluateScriptInIsolatedWorld( const CppArgumentList& args, CppVariant* result) { - if (args.size() > 0 && args[0].isString()) { - WebScriptSource source(WebString::fromUTF8(args[0].ToString())); - shell_->webView()->mainFrame()->executeScriptInNewWorld(&source, 1, 1); + if (args.size() >= 2 && args[0].isNumber() && args[1].isString()) { + WebScriptSource source(WebString::fromUTF8(args[1].ToString())); + // This relies on the iframe focusing itself when it loads. This is a bit + // sketchy, but it seems to be what other tests do. + shell_->webView()->focusedFrame()->executeScriptInIsolatedWorld( + args[0].ToInt32(), &source, 1, 1); } result->SetNull(); } |