diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-25 22:10:50 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-25 22:10:50 +0000 |
commit | db7331aecb1f0c01aecf4cd4627d08a8d5b08bc2 (patch) | |
tree | 5a33fc21cb1628462f9e365add27aeaf058d60fc /chrome/browser/extensions | |
parent | f56abff188b90b7f2d67a094930d7d9407df507d (diff) | |
download | chromium_src-db7331aecb1f0c01aecf4cd4627d08a8d5b08bc2.zip chromium_src-db7331aecb1f0c01aecf4cd4627d08a8d5b08bc2.tar.gz chromium_src-db7331aecb1f0c01aecf4cd4627d08a8d5b08bc2.tar.bz2 |
Allow users to enable extensions in incognito. Requires
--enable-experimental-extension-apis . The UI needs work. Tab and window
events are hooked up so that they work with incognito tabs/windows when
enabled.
BUG=32365
BUG=36292
Review URL: http://codereview.chromium.org/657041
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40057 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
39 files changed, 385 insertions, 141 deletions
diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc index da16d80..27ccf3f 100644 --- a/chrome/browser/extensions/execute_code_in_tab_function.cc +++ b/chrome/browser/extensions/execute_code_in_tab_function.cc @@ -48,7 +48,7 @@ bool ExecuteCodeInTabFunction::RunImpl() { Value* tab_value = NULL; EXTENSION_FUNCTION_VALIDATE(args->Get(0, &tab_value)); if (tab_value->IsType(Value::TYPE_NULL)) { - browser = dispatcher()->GetBrowser(); + browser = GetBrowser(); if (!browser) { error_ = keys::kNoCurrentWindowError; return false; @@ -57,8 +57,9 @@ bool ExecuteCodeInTabFunction::RunImpl() { return false; } else { EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_)); - if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(), &browser, - NULL, &contents, NULL)) { + if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(), + include_incognito(), + &browser, NULL, &contents, NULL)) { return false; } } @@ -127,7 +128,8 @@ void ExecuteCodeInTabFunction::DidLoadFile(bool success, bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) { TabContents* contents = NULL; Browser* browser = NULL; - if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(), &browser, NULL, + if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(), + include_incognito(), &browser, NULL, &contents, NULL) && contents && browser) { SendResponse(false); return false; diff --git a/chrome/browser/extensions/extension_accessibility_api.cc b/chrome/browser/extensions/extension_accessibility_api.cc index 2ea3775..38745a7 100644 --- a/chrome/browser/extensions/extension_accessibility_api.cc +++ b/chrome/browser/extensions/extension_accessibility_api.cc @@ -157,8 +157,8 @@ void ExtensionAccessibilityEventRouter::DispatchEvent( const char* event_name, const std::string& json_args) { if (enabled_ && profile && profile->GetExtensionMessageService()) { - profile->GetExtensionMessageService()-> - DispatchEventToRenderers(event_name, json_args); + profile->GetExtensionMessageService()->DispatchEventToRenderers( + event_name, json_args, profile->IsOffTheRecord()); } } diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc index 81848f3..a67b716 100644 --- a/chrome/browser/extensions/extension_bookmark_manager_api.cc +++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc @@ -170,8 +170,8 @@ void ExtensionBookmarkManagerEventRouter::DispatchEvent(const char* event_name, std::string json_args; base::JSONWriter::Write(args, false, &json_args); - profile_->GetExtensionMessageService()-> - DispatchEventToRenderers(event_name, json_args); + profile_->GetExtensionMessageService()->DispatchEventToRenderers( + event_name, json_args, profile_->IsOffTheRecord()); } void ExtensionBookmarkManagerEventRouter::DispatchDragEvent( diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc index 993cb05..d561e2a 100644 --- a/chrome/browser/extensions/extension_bookmarks_module.cc +++ b/chrome/browser/extensions/extension_bookmarks_module.cc @@ -170,8 +170,8 @@ void ExtensionBookmarkEventRouter::DispatchEvent(Profile *profile, const char* event_name, const std::string json_args) { if (profile->GetExtensionMessageService()) { - profile->GetExtensionMessageService()-> - DispatchEventToRenderers(event_name, json_args); + profile->GetExtensionMessageService()->DispatchEventToRenderers( + event_name, json_args, profile->IsOffTheRecord()); } } diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc index 388863a..9b379bc 100644 --- a/chrome/browser/extensions/extension_browser_event_router.cc +++ b/chrome/browser/extensions/extension_browser_event_router.cc @@ -88,8 +88,8 @@ static void DispatchEvent(Profile* profile, const char* event_name, const std::string json_args) { if (profile->GetExtensionMessageService()) { - profile->GetExtensionMessageService()-> - DispatchEventToRenderers(event_name, json_args); + profile->GetExtensionMessageService()->DispatchEventToRenderers( + event_name, json_args, profile->IsOffTheRecord()); } } @@ -437,8 +437,8 @@ void ExtensionBrowserEventRouter::PageActionExecuted( DispatchOldPageActionEvent(profile, extension_id, page_action_id, tab_id, url, button); TabContents* tab_contents = NULL; - if (!ExtensionTabUtil::GetTabById(tab_id, profile, NULL, NULL, &tab_contents, - NULL)) { + if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(), + NULL, NULL, &tab_contents, NULL)) { return; } std::string event_name = std::string("pageAction/") + extension_id; diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc index 9b4ddd8..d96d6dc 100644 --- a/chrome/browser/extensions/extension_browsertest.cc +++ b/chrome/browser/extensions/extension_browsertest.cc @@ -51,7 +51,8 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) { command_line->AppendSwitch(switches::kEnableExtensionToolstrips); } -bool ExtensionBrowserTest::LoadExtension(const FilePath& path) { +bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path, + bool incognito_enabled) { ExtensionsService* service = browser()->profile()->GetExtensionsService(); size_t num_before = service->extensions()->size(); { @@ -67,9 +68,22 @@ bool ExtensionBrowserTest::LoadExtension(const FilePath& path) { if (num_after != (num_before + 1)) return false; + if (incognito_enabled) { + Extension* extension = service->extensions()->at(num_after - 1); + service->SetIsIncognitoEnabled(extension->id(), true); + } + return WaitForExtensionHostsToLoad(); } +bool ExtensionBrowserTest::LoadExtension(const FilePath& path) { + return LoadExtensionImpl(path, false); +} + +bool ExtensionBrowserTest::LoadExtensionIncognito(const FilePath& path) { + return LoadExtensionImpl(path, true); +} + // This class is used to simulate an installation abort by the user. class MockAbortExtensionInstallUI : public ExtensionInstallUI { public: diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h index 263f582..8a34903 100644 --- a/chrome/browser/extensions/extension_browsertest.h +++ b/chrome/browser/extensions/extension_browsertest.h @@ -25,6 +25,9 @@ class ExtensionBrowserTest virtual void SetUpCommandLine(CommandLine* command_line); bool LoadExtension(const FilePath& path); + // Same as above, but enables the extension in incognito mode first. + bool LoadExtensionIncognito(const FilePath& path); + // |expected_change| indicates how many extensions should be installed (or // disabled, if negative). // 1 means you expect a new install, 0 means you expect an upgrade, -1 means @@ -93,6 +96,7 @@ class ExtensionBrowserTest bool InstallOrUpdateExtension(const std::string& id, const FilePath& path, bool should_cancel, int expected_change); + bool LoadExtensionImpl(const FilePath& path, bool incognito_enabled); bool WaitForExtensionHostsToLoad(); diff --git a/chrome/browser/extensions/extension_devtools_bridge.cc b/chrome/browser/extensions/extension_devtools_bridge.cc index c9a5f50..a6399d8 100644 --- a/chrome/browser/extensions/extension_devtools_bridge.cc +++ b/chrome/browser/extensions/extension_devtools_bridge.cc @@ -36,7 +36,8 @@ bool ExtensionDevToolsBridge::RegisterAsDevToolsClientHost() { TabStripModel* tab_strip; TabContents* contents; int tab_index; - if (ExtensionTabUtil::GetTabById(tab_id_, profile_, &browser, &tab_strip, + if (ExtensionTabUtil::GetTabById(tab_id_, profile_, true, + &browser, &tab_strip, &contents, &tab_index)) { DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); devtools_manager->RegisterDevToolsClientHostFor( @@ -63,8 +64,8 @@ void ExtensionDevToolsBridge::InspectedTabClosing() { // TODO(knorton): Remove this event in favor of the standard tabs.onRemoved // event in extensions. std::string json("[{}]"); - profile_->GetExtensionMessageService()-> - DispatchEventToRenderers(on_tab_close_event_name_, json); + profile_->GetExtensionMessageService()->DispatchEventToRenderers( + on_tab_close_event_name_, json, profile_->IsOffTheRecord()); // This may result in this object being destroyed. extension_devtools_manager_->BridgeClosingForTab(tab_id_); @@ -87,7 +88,7 @@ void ExtensionDevToolsBridge::OnRpcMessage(const DevToolsMessageData& data) { && data.method_name == kApuPageEventMessageName) { std::string json = StringPrintf("[%s]", data.arguments[0].c_str()); profile_->GetExtensionMessageService()->DispatchEventToRenderers( - on_page_event_name_, json); + on_page_event_name_, json, profile_->IsOffTheRecord()); } } diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc index de2d13b..b39b15b 100644 --- a/chrome/browser/extensions/extension_dom_ui.cc +++ b/chrome/browser/extensions/extension_dom_ui.cc @@ -76,11 +76,19 @@ void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message, has_callback); } -Browser* ExtensionDOMUI::GetBrowser() const { +Browser* ExtensionDOMUI::GetBrowser(bool include_incognito) const { + Browser* browser = NULL; TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate(); - if (tab_contents_delegate) - return tab_contents_delegate->GetBrowser(); - return NULL; + if (tab_contents_delegate) { + browser = tab_contents_delegate->GetBrowser(); + if (browser && browser->profile()->IsOffTheRecord() && !include_incognito) { + // Fall back to the toplevel regular browser if we don't want to include + // incognito browsers. + browser = BrowserList::GetLastActiveWithProfile( + browser->profile()->GetOriginalProfile()); + } + } + return browser; } Profile* ExtensionDOMUI::GetProfile() { diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h index 59a89a8..9d85ccb 100644 --- a/chrome/browser/extensions/extension_dom_ui.h +++ b/chrome/browser/extensions/extension_dom_ui.h @@ -41,11 +41,12 @@ class ExtensionDOMUI bool has_callback); // ExtensionFunctionDispatcher::Delegate - virtual Browser* GetBrowser() const; + virtual Browser* GetBrowser(bool include_incognito) const; virtual ExtensionDOMUI* GetExtensionDOMUI() { return this; } virtual gfx::NativeWindow GetFrameNativeWindow(); // ExtensionPopupHost::Delegate + virtual Browser* GetBrowser() const { return GetBrowser(true); } virtual RenderViewHost* GetRenderViewHost(); virtual Profile* GetProfile(); virtual gfx::NativeView GetNativeViewOfHost(); diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index 6db6443..06f69ab 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -68,6 +68,9 @@ class ExtensionFunction : public base::RefCounted<ExtensionFunction> { void set_has_callback(bool has_callback) { has_callback_ = has_callback; } bool has_callback() { return has_callback_; } + void set_include_incognito(bool include) { include_incognito_ = include; } + bool include_incognito() { return include_incognito_; } + // Execute the API. Clients should call set_raw_args() and // set_request_id() before calling this method. Derived classes should be // ready to return raw_result() and error() before returning from this @@ -88,6 +91,10 @@ class ExtensionFunction : public base::RefCounted<ExtensionFunction> { return NULL; } + Browser* GetBrowser() { + return dispatcher()->GetBrowser(include_incognito_); + } + // The peer to the dispatcher that will service this extension function call. scoped_refptr<ExtensionFunctionDispatcher::Peer> peer_; @@ -101,6 +108,9 @@ class ExtensionFunction : public base::RefCounted<ExtensionFunction> { // of this call. bool has_callback_; + // True if this callback should include information from incognito contexts. + bool include_incognito_; + DISALLOW_COPY_AND_ASSIGN(ExtensionFunction); }; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 69e4d54..35b73a5 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -174,6 +174,7 @@ void FactoryRegistry::ResetFunctions() { RegisterFunction<ExtensionTestFailFunction>(); RegisterFunction<ExtensionTestLogFunction>(); RegisterFunction<ExtensionTestQuotaResetFunction>(); + RegisterFunction<ExtensionTestCreateIncognitoTabFunction>(); // Accessibility. RegisterFunction<GetFocusedControlFunction>(); @@ -212,7 +213,7 @@ ExtensionFunction* FactoryRegistry::NewFunction(const std::string& name) { gfx::NativeWindow ExtensionFunctionDispatcher::Delegate:: GetFrameNativeWindow() { - Browser* browser = GetBrowser(); + Browser* browser = GetBrowser(true); // If a browser is bound to this dispatcher, then return the widget hosting // the window. Extensions hosted in ExternalTabContainer objects may not // have a running browser instance. @@ -266,6 +267,9 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( epm->RegisterExtensionProcess(extension_id(), render_view_host->process()->id()); + bool incognito_enabled = + profile()->GetExtensionsService()->IsIncognitoEnabled(extension->id()); + // Update the extension permissions. Doing this each time we create an EFD // ensures that new processes are informed of permissions for newly installed // extensions. @@ -273,6 +277,8 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( extension->id(), extension->api_permissions())); render_view_host->Send(new ViewMsg_Extension_SetHostPermissions( extension->url(), extension->host_permissions())); + render_view_host->Send(new ViewMsg_Extension_ExtensionSetIncognitoEnabled( + extension->id(), incognito_enabled)); } ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { @@ -280,8 +286,8 @@ ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { peer_->dispatcher_ = NULL; } -Browser* ExtensionFunctionDispatcher::GetBrowser() { - return delegate_->GetBrowser(); +Browser* ExtensionFunctionDispatcher::GetBrowser(bool include_incognito) { + return delegate_->GetBrowser(include_incognito); } ExtensionPopupHost* ExtensionFunctionDispatcher::GetPopupHost() { @@ -324,6 +330,8 @@ void ExtensionFunctionDispatcher::HandleRequest(const std::string& name, function->SetArgs(args); function->set_request_id(request_id); function->set_has_callback(has_callback); + function->set_include_incognito( + profile()->GetExtensionsService()->IsIncognitoEnabled(extension_id())); ExtensionsService* service = profile()->GetExtensionsService(); DCHECK(service); diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h index 38376e7..1bdfca2 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.h +++ b/chrome/browser/extensions/extension_function_dispatcher.h @@ -34,7 +34,10 @@ class ExtensionFunctionDispatcher { public: class Delegate { public: - virtual Browser* GetBrowser() const = 0; + // Returns the browser that this delegate is associated with. If the browser + // is incognito, but |include_incognito_windows| is false, we fall back to + // the toplevel browser in the original profile. + virtual Browser* GetBrowser(bool include_incognito_windows) const = 0; // Returns the gfx::NativeWindow that contains the view hosting the // environment in which the function dispatcher resides. @@ -89,7 +92,9 @@ class ExtensionFunctionDispatcher { // Gets the browser extension functions should operate relative to. For // example, for positioning windows, or alert boxes, or creating tabs. - Browser* GetBrowser(); + // If |include_incognito| is false, and the appropriate browser is incognito, + // we will fall back to a regular browser window or NULL if unavailable. + Browser* GetBrowser(bool include_incognito); // Get the extension popup hosting environment for the ExtensionHost // or ExtensionDOMUI associted with this dispatcher. diff --git a/chrome/browser/extensions/extension_history_api.cc b/chrome/browser/extensions/extension_history_api.cc index c1808d5..75ed48a 100644 --- a/chrome/browser/extensions/extension_history_api.cc +++ b/chrome/browser/extensions/extension_history_api.cc @@ -140,8 +140,8 @@ void ExtensionHistoryEventRouter::DispatchEvent(Profile* profile, const char* event_name, const std::string& json_args) { if (profile && profile->GetExtensionMessageService()) { - profile->GetExtensionMessageService()-> - DispatchEventToRenderers(event_name, json_args); + profile->GetExtensionMessageService()->DispatchEventToRenderers( + event_name, json_args, profile->IsOffTheRecord()); } } diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index e139899..5c01d69 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -483,8 +483,8 @@ void ExtensionHost::ProcessDOMUIMessage(const std::string& message, int request_id, bool has_callback) { if (extension_function_dispatcher_.get()) { - extension_function_dispatcher_->HandleRequest(message, content, request_id, - has_callback); + extension_function_dispatcher_->HandleRequest( + message, content, request_id, has_callback); } } @@ -612,19 +612,28 @@ void ExtensionHost::HandleMouseLeave() { #endif } -Browser* ExtensionHost::GetBrowser() const { +Browser* ExtensionHost::GetBrowser(bool include_incognito) const { + Browser* browser = NULL; + if (view_.get()) - return view_->browser(); + browser = view_->browser(); - Profile* profile = render_view_host()->process()->profile(); - Browser* browser = BrowserList::GetLastActiveWithProfile(profile); + if (!browser || + (browser->profile()->IsOffTheRecord() && !include_incognito)) { + Profile* profile = render_view_host()->process()->profile(); + // Make sure we don't return an incognito browser without proper access. + if (!include_incognito) + profile = profile->GetOriginalProfile(); - // It's possible for a browser to exist, but to have never been active. - // This can happen if you launch the browser on a machine without an active - // desktop (a headless buildbot) or if you quickly give another app focus - // at launch time. This is easy to do with browser_tests. - if (!browser) - browser = BrowserList::FindBrowserWithProfile(profile); + browser = BrowserList::GetLastActiveWithProfile(profile); + + // It's possible for a browser to exist, but to have never been active. + // This can happen if you launch the browser on a machine without an active + // desktop (a headless buildbot) or if you quickly give another app focus + // at launch time. This is easy to do with browser_tests. + if (!browser) + browser = BrowserList::FindBrowserWithProfile(profile); + } // TODO(erikkay): can this still return NULL? Is Rafael's comment still // valid here? diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index fd155d7..83f2cb2 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -196,10 +196,11 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate, // If this ExtensionHost has a view, this returns the Browser that view is a // part of. If this is a global background page, we use the active Browser // instead. - virtual Browser* GetBrowser() const; + virtual Browser* GetBrowser(bool include_incognito) const; virtual ExtensionHost* GetExtensionHost() { return this; } // ExtensionPopupHost::Delegate + virtual Browser* GetBrowser() const { return GetBrowser(true); } virtual RenderViewHost* GetRenderViewHost() { return render_view_host(); } virtual gfx::NativeView GetNativeViewOfHost() { return view()->native_view(); diff --git a/chrome/browser/extensions/incognito_noscript_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc index d4e71a5..29de8fb 100755 --- a/chrome/browser/extensions/incognito_noscript_apitest.cc +++ b/chrome/browser/extensions/extension_incognito_apitest.cc @@ -5,7 +5,8 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_window.h" -#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/browser/extensions/browser_action_test_util.h" +#include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/extensions/user_script_master.h" #include "chrome/browser/profile.h" @@ -24,7 +25,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") - .AppendASCII("incognito_no_script"))); + .AppendASCII("incognito").AppendASCII("content_scripts"))); // Open incognito window and navigate to test page. ui_test_utils::OpenURLOffTheRecord(browser()->profile(), @@ -56,21 +57,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) { // that loads to "modified". CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); - ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") - .AppendASCII("incognito_no_script"))); + ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test") + .AppendASCII("incognito").AppendASCII("content_scripts"))); // Dummy extension #2. ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") .AppendASCII("content_scripts").AppendASCII("isolated_world1"))); - // Now enable the incognito_no_script extension in incognito mode, and ensure - // that page titles are modified. - ExtensionsService* service = browser()->profile()->GetExtensionsService(); - service->extension_prefs()->SetIsIncognitoEnabled( - service->extensions()->at(1)->id(), true); - browser()->profile()->GetUserScriptMaster()->ReloadExtensionForTesting( - service->extensions()->at(1)); - // Open incognito window and navigate to test page. ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("http://www.example.com:1337/files/extensions/test_file.html")); @@ -86,3 +79,66 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) { &result); EXPECT_TRUE(result); } + +// Tests that the APIs in an incognito-enabled extension work properly. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) { + host_resolver()->AddRule("*", "127.0.0.1"); + StartHTTPServer(); + + ResultCatcher catcher; + + // Open incognito window and navigate to test page. + ui_test_utils::OpenURLOffTheRecord(browser()->profile(), + GURL("http://www.example.com:1337/files/extensions/test_file.html")); + + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_ + .AppendASCII("incognito").AppendASCII("apis"))); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + +// Tests that the APIs in an incognito-disabled extension don't see incognito +// events or callbacks. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) { + host_resolver()->AddRule("*", "127.0.0.1"); + StartHTTPServer(); + + ResultCatcher catcher; + + // Open incognito window and navigate to test page. + ui_test_utils::OpenURLOffTheRecord(browser()->profile(), + GURL("http://www.example.com:1337/files/extensions/test_file.html")); + + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + ASSERT_TRUE(LoadExtension(test_data_dir_ + .AppendASCII("incognito").AppendASCII("apis_disabled"))); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + +// Test that opening a popup from an incognito browser window works properly. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) { + host_resolver()->AddRule("*", "127.0.0.1"); + StartHTTPServer(); + + ResultCatcher catcher; + + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_ + .AppendASCII("incognito").AppendASCII("popup"))); + + // Open incognito window and navigate to test page. + ui_test_utils::OpenURLOffTheRecord(browser()->profile(), + GURL("http://www.example.com:1337/files/extensions/test_file.html")); + Browser* incognito_browser = BrowserList::FindBrowserWithType( + browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL); + + // Simulate the incognito's browser action being clicked. + BrowserActionTestUtil(incognito_browser).Press(0); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); +} diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index 9339196..dd464ea 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -92,10 +92,12 @@ static void DispatchOnMessage(const ExtensionMessageService::MessagePort& port, static void DispatchEvent(const ExtensionMessageService::MessagePort& port, const std::string& event_name, - const std::string& event_args) { + const std::string& event_args, + bool has_incognito_data) { ListValue args; args.Set(0, Value::CreateStringValue(event_name)); args.Set(1, Value::CreateStringValue(event_args)); + args.Set(2, Value::CreateBooleanValue(has_incognito_data)); port.sender->Send(new ViewMsg_ExtensionMessageInvoke( port.routing_id, ExtensionMessageService::kDispatchEvent, args)); } @@ -283,7 +285,7 @@ void ExtensionMessageService::OpenChannelToTabOnUIThread( TabContents* contents = NULL; MessagePort receiver; receiver.debug_info = 2; - if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), + if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), true, NULL, NULL, &contents, NULL)) { receiver.sender = contents->render_view_host(); receiver.routing_id = contents->render_view_host()->routing_id(); @@ -451,7 +453,8 @@ void ExtensionMessageService::PostMessageFromRenderer( } void ExtensionMessageService::DispatchEventToRenderers( - const std::string& event_name, const std::string& event_args) { + const std::string& event_name, const std::string& event_args, + bool has_incognito_data) { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); std::set<int>& pids = listeners_[event_name]; @@ -467,7 +470,7 @@ void ExtensionMessageService::DispatchEventToRenderers( continue; } - DispatchEvent(renderer, event_name, event_args); + DispatchEvent(renderer, event_name, event_args, has_incognito_data); } } diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h index b04780c..6b8ade6 100644 --- a/chrome/browser/extensions/extension_message_service.h +++ b/chrome/browser/extensions/extension_message_service.h @@ -82,7 +82,8 @@ class ExtensionMessageService // Send an event to every registered extension renderer. void DispatchEventToRenderers( - const std::string& event_name, const std::string& event_args); + const std::string& event_name, const std::string& event_args, + bool has_incognito_data); // Given an extension ID, opens a channel between the given // automation "port" or DevTools service and that extension. the diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc index 1379b2f..5fcbf45 100644 --- a/chrome/browser/extensions/extension_page_actions_module.cc +++ b/chrome/browser/extensions/extension_page_actions_module.cc @@ -70,7 +70,8 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) { // Find the TabContents that contains this tab id. TabContents* contents = NULL; - ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents, NULL); + ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), + NULL, NULL, &contents, NULL); if (!contents) { error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError, IntToString(tab_id)); @@ -102,7 +103,8 @@ bool PageActionFunction::InitCommon(int tab_id) { // Find the TabContents that contains this tab id. contents_ = NULL; - ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents_, NULL); + ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), + NULL, NULL, &contents_, NULL); if (!contents_) { error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError, IntToString(tab_id)); diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc index 48e414c..d6edbc0 100644 --- a/chrome/browser/extensions/extension_popup_api.cc +++ b/chrome/browser/extensions/extension_popup_api.cc @@ -155,7 +155,7 @@ bool PopupShowFunction::RunImpl() { BubbleBorder::ArrowLocation arrow_location = (NULL != dispatcher()->GetExtensionHost()) ? BubbleBorder::BOTTOM_LEFT : BubbleBorder::TOP_LEFT; - popup_ = ExtensionPopup::Show(url, dispatcher()->GetBrowser(), + popup_ = ExtensionPopup::Show(url, GetBrowser(), dispatcher()->profile(), dispatcher()->GetFrameNativeWindow(), rect, @@ -238,5 +238,6 @@ void PopupEventRouter::OnPopupClosed(Profile* profile, profile->GetExtensionMessageService()->DispatchEventToRenderers( full_event_name, - base::JSONWriter::kEmptyArray); + base::JSONWriter::kEmptyArray, + profile->IsOffTheRecord()); } diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index 3121d3c..7ecee27 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -232,6 +232,19 @@ void ExtensionProcessManager::Observe(NotificationType type, break; } + case NotificationType::EXTENSION_INCOGNITO_CHANGED: { + Extension* extension = + Details<std::pair<Extension*, bool> >(details).ptr()->first; + bool incognito_enabled = + Details<std::pair<Extension*, bool> >(details).ptr()->second; + RenderProcessHost* rph = GetExtensionProcess(extension->id()); + if (rph) { + rph->Send(new ViewMsg_Extension_ExtensionSetIncognitoEnabled( + extension->id(), incognito_enabled)); + } + break; + } + case NotificationType::EXTENSION_HOST_DESTROYED: { ExtensionHost* host = Details<ExtensionHost>(details).ptr(); all_hosts_.erase(host); diff --git a/chrome/browser/extensions/extension_processes_api.cc b/chrome/browser/extensions/extension_processes_api.cc index 8495d9d..fda8c7f 100644 --- a/chrome/browser/extensions/extension_processes_api.cc +++ b/chrome/browser/extensions/extension_processes_api.cc @@ -24,8 +24,8 @@ bool GetProcessForTabFunction::RunImpl() { TabContents* contents = NULL; int tab_index = -1; - if (!ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, - &contents, &tab_index)) + if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), + NULL, NULL, &contents, &tab_index)) return false; int process_id = contents->GetRenderProcessHost()->id(); diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc index 21dcd12..b6e66f6 100644 --- a/chrome/browser/extensions/extension_protocols.cc +++ b/chrome/browser/extensions/extension_protocols.cc @@ -6,12 +6,16 @@ #include "base/string_util.h" #include "chrome/browser/net/chrome_url_request_context.h" +#include "chrome/browser/renderer_host/resource_dispatcher_host.h" +#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/url_constants.h" #include "googleurl/src/url_util.h" +#include "net/base/net_errors.h" #include "net/url_request/url_request_file_job.h" +#include "net/url_request/url_request_error_job.h" // Factory registered with URLRequest to create URLRequestJobs for extension:// // URLs. @@ -20,6 +24,16 @@ static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request, ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(request->context()); + // Don't allow toplevel navigations to extension resources in incognito mode. + // This is because an extension must run in a single process, and an incognito + // tab prevents that. + // TODO(mpcomplete): better error code. + const ResourceDispatcherHostRequestInfo* info = + ResourceDispatcherHost::InfoForRequest(request); + if (context->is_off_the_record() && + info && info->resource_type() == ResourceType::MAIN_FRAME) + return new URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE); + // chrome-extension://extension-id/resource/path.js FilePath directory_path = context->GetPathForExtension(request->url().host()); if (directory_path.value().empty()) { diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index e00964d..c602cf6 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -36,11 +36,14 @@ namespace keys = extension_tabs_module_constants; // message if the window cannot be found by id. static Browser* GetBrowserInProfileWithId(Profile* profile, const int window_id, + bool include_incognito, std::string* error_message); -// |error_message| can optionally be passed in a will be set with an appropriate -// message if the tab cannot be found by id. -static bool GetTabById(int tab_id, Profile* profile, Browser** browser, +// |error_message| can optionally be passed in and will be set with an +// appropriate message if the tab cannot be found by id. +static bool GetTabById(int tab_id, Profile* profile, + bool include_incognito, + Browser** browser, TabStripModel** tab_strip, TabContents** contents, int* tab_index, std::string* error_message); @@ -117,6 +120,8 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue( result->SetBoolean(keys::kSelectedKey, tab_strip && tab_index == tab_strip->selected_index()); result->SetString(keys::kTitleKey, UTF16ToWide(contents->GetTitle())); + result->SetBoolean(keys::kIncognitoKey, + contents->profile()->IsOffTheRecord()); if (status != TAB_LOADING) { NavigationEntry* entry = contents->controller().GetActiveEntry(); @@ -140,6 +145,8 @@ DictionaryValue* ExtensionTabUtil::CreateWindowValue(const Browser* browser, if (browser->window()) focused = browser->window()->IsActive(); + result->SetBoolean(keys::kIncognitoKey, + browser->profile()->IsOffTheRecord()); result->SetBoolean(keys::kFocusedKey, focused); gfx::Rect bounds = browser->window()->GetRestoredBounds(); @@ -173,6 +180,7 @@ bool ExtensionTabUtil::GetDefaultTab(Browser* browser, TabContents** contents, } bool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile, + bool include_incognito, Browser** browser, TabStripModel** tab_strip, TabContents** contents, @@ -180,10 +188,13 @@ bool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile, Browser* target_browser; TabStripModel* target_tab_strip; TabContents* target_contents; + Profile* incognito_profile = + include_incognito ? profile->GetOffTheRecordProfile() : NULL; for (BrowserList::const_iterator iter = BrowserList::begin(); iter != BrowserList::end(); ++iter) { target_browser = *iter; - if (target_browser->profile() == profile) { + if (target_browser->profile() == profile || + target_browser->profile() == incognito_profile) { target_tab_strip = target_browser->tabstrip_model(); for (int i = 0; i < target_tab_strip->count(); ++i) { target_contents = target_tab_strip->GetTabContentsAt(i); @@ -210,7 +221,8 @@ bool GetWindowFunction::RunImpl() { int window_id; EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); - Browser* browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + Browser* browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); if (!browser) return false; @@ -219,7 +231,7 @@ bool GetWindowFunction::RunImpl() { } bool GetCurrentWindowFunction::RunImpl() { - Browser* browser = dispatcher()->GetBrowser(); + Browser* browser = GetBrowser(); if (!browser) { error_ = keys::kNoCurrentWindowError; return false; @@ -250,10 +262,13 @@ bool GetAllWindowsFunction::RunImpl() { } result_.reset(new ListValue()); + Profile* incognito_profile = + include_incognito() ? profile()->GetOffTheRecordProfile() : NULL; for (BrowserList::const_iterator browser = BrowserList::begin(); browser != BrowserList::end(); ++browser) { // Only examine browsers in the current profile. - if ((*browser)->profile() == profile()) { + if ((*browser)->profile() == profile() || + (*browser)->profile() == incognito_profile) { static_cast<ListValue*>(result_.get())-> Append(ExtensionTabUtil::CreateWindowValue(*browser, populate_tabs)); } @@ -297,7 +312,7 @@ bool CreateWindowFunction::RunImpl() { // NOTE(rafaelw): It's ok if dispatcher_->GetBrowser() returns NULL here. // GetBrowserWindowBounds will default to saved "default" values for the app. WindowSizer::GetBrowserWindowBounds(std::wstring(), empty_bounds, - dispatcher()->GetBrowser(), &bounds, + GetBrowser(), &bounds, &maximized); // Any part of the bounds can optionally be set by the caller. @@ -351,7 +366,8 @@ bool UpdateWindowFunction::RunImpl() { DictionaryValue* update_props; EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(1, &update_props)); - Browser* browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + Browser* browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); if (!browser) return false; @@ -397,7 +413,8 @@ bool RemoveWindowFunction::RunImpl() { int window_id; EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); - Browser* browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + Browser* browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); if (!browser) return false; @@ -415,9 +432,10 @@ bool GetSelectedTabFunction::RunImpl() { if (!args_->IsType(Value::TYPE_NULL)) { EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); - browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); } else { - browser = dispatcher()->GetBrowser(); + browser = GetBrowser(); if (!browser) error_ = keys::kNoCurrentWindowError; } @@ -441,9 +459,10 @@ bool GetAllTabsInWindowFunction::RunImpl() { int window_id = -1; if (!args_->IsType(Value::TYPE_NULL)) { EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); - browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); } else { - browser = dispatcher()->GetBrowser(); + browser = GetBrowser(); if (!browser) error_ = keys::kNoCurrentWindowError; } @@ -465,9 +484,10 @@ bool CreateTabFunction::RunImpl() { if (args->HasKey(keys::kWindowIdKey)) { EXTENSION_FUNCTION_VALIDATE(args->GetInteger( keys::kWindowIdKey, &window_id)); - browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); } else { - browser = dispatcher()->GetBrowser(); + browser = GetBrowser(); if (!browser) error_ = keys::kNoCurrentWindowError; } @@ -536,8 +556,8 @@ bool GetTabFunction::RunImpl() { TabStripModel* tab_strip = NULL; TabContents* contents = NULL; int tab_index = -1; - if (!GetTabById(tab_id, profile(), NULL, &tab_strip, &contents, &tab_index, - &error_)) + if (!GetTabById(tab_id, profile(), include_incognito(), + NULL, &tab_strip, &contents, &tab_index, &error_)) return false; result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip, @@ -556,8 +576,8 @@ bool UpdateTabFunction::RunImpl() { TabStripModel* tab_strip = NULL; TabContents* contents = NULL; int tab_index = -1; - if (!GetTabById(tab_id, profile(), NULL, &tab_strip, &contents, &tab_index, - &error_)) + if (!GetTabById(tab_id, profile(), include_incognito(), + NULL, &tab_strip, &contents, &tab_index, &error_)) return false; if (tab_strip->IsTabPinned(tab_index)) { @@ -645,8 +665,9 @@ bool MoveTabFunction::RunImpl() { TabStripModel* source_tab_strip = NULL; TabContents* contents = NULL; int tab_index = -1; - if (!GetTabById(tab_id, profile(), &source_browser, &source_tab_strip, - &contents, &tab_index, &error_)) + if (!GetTabById(tab_id, profile(), include_incognito(), + &source_browser, &source_tab_strip, &contents, + &tab_index, &error_)) return false; if (update_props->HasKey(keys::kWindowIdKey)) { @@ -655,7 +676,7 @@ bool MoveTabFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger( keys::kWindowIdKey, &window_id)); target_browser = GetBrowserInProfileWithId(profile(), window_id, - &error_); + include_incognito(), &error_); if (!target_browser) return false; @@ -708,7 +729,8 @@ bool RemoveTabFunction::RunImpl() { Browser* browser = NULL; TabContents* contents = NULL; - if (!GetTabById(tab_id, profile(), &browser, NULL, &contents, NULL, &error_)) + if (!GetTabById(tab_id, profile(), include_incognito(), + &browser, NULL, &contents, NULL, &error_)) return false; int tab_index = browser->GetIndexOfController(&contents->controller()); @@ -734,9 +756,10 @@ bool CaptureVisibleTabFunction::RunImpl() { if (!args_->IsType(Value::TYPE_NULL)) { EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id)); - browser = GetBrowserInProfileWithId(profile(), window_id, &error_); + browser = GetBrowserInProfileWithId(profile(), window_id, + include_incognito(), &error_); } else { - browser = dispatcher()->GetBrowser(); + browser = GetBrowser(); } if (!browser) { @@ -856,14 +879,14 @@ bool DetectTabLanguageFunction::RunImpl() { // in the current window. if (!args_->IsType(Value::TYPE_NULL)) { EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id)); - if (!GetTabById(tab_id, profile(), &browser, NULL, &contents, NULL, - &error_)) { + if (!GetTabById(tab_id, profile(), include_incognito(), + &browser, NULL, &contents, NULL, &error_)) { return false; } if (!browser || !contents) return false; } else { - browser = dispatcher()->GetBrowser(); + browser = GetBrowser(); if (!browser) return false; contents = browser->tabstrip_model()->GetSelectedTabContents(); @@ -924,10 +947,14 @@ void DetectTabLanguageFunction::GotLanguage(const std::string& language) { static Browser* GetBrowserInProfileWithId(Profile* profile, const int window_id, + bool include_incognito, std::string* error_message) { + Profile* incognito_profile = + include_incognito ? profile->GetOffTheRecordProfile() : NULL; for (BrowserList::const_iterator browser = BrowserList::begin(); - browser != BrowserList::end(); ++browser) { - if ((*browser)->profile() == profile && + browser != BrowserList::end(); ++browser) { + if (((*browser)->profile() == profile || + (*browser)->profile() == incognito_profile) && ExtensionTabUtil::GetWindowId(*browser) == window_id) return *browser; } @@ -939,13 +966,15 @@ static Browser* GetBrowserInProfileWithId(Profile* profile, return NULL; } -static bool GetTabById(int tab_id, Profile* profile, Browser** browser, +static bool GetTabById(int tab_id, Profile* profile, + bool include_incognito, + Browser** browser, TabStripModel** tab_strip, TabContents** contents, int* tab_index, std::string* error_message) { - if (ExtensionTabUtil::GetTabById(tab_id, profile, browser, tab_strip, - contents, tab_index)) + if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito, + browser, tab_strip, contents, tab_index)) return true; if (error_message) diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h index 5282a17..c7d36f8 100644 --- a/chrome/browser/extensions/extension_tabs_module.h +++ b/chrome/browser/extensions/extension_tabs_module.h @@ -45,7 +45,8 @@ class ExtensionTabUtil { int* tab_id); // Any out parameter (|browser|, |tab_strip|, |contents|, & |tab_index|) may // be NULL and will not be set within the function. - static bool GetTabById(int tab_id, Profile* profile, Browser** browser, + static bool GetTabById(int tab_id, Profile* profile, bool incognito_enabled, + Browser** browser, TabStripModel** tab_strip, TabContents** contents, int* tab_index); diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc index 96176ea..6a75742 100644 --- a/chrome/browser/extensions/extension_tabs_module_constants.cc +++ b/chrome/browser/extensions/extension_tabs_module_constants.cc @@ -32,6 +32,7 @@ const wchar_t kTopKey[] = L"top"; const wchar_t kUrlKey[] = L"url"; const wchar_t kWidthKey[] = L"width"; const wchar_t kWindowIdKey[] = L"windowId"; +const wchar_t kIncognitoKey[] = L"incognito"; const char kStatusValueComplete[] = "complete"; const char kStatusValueLoading[] = "loading"; diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h index f51bc5a..9f72501 100644 --- a/chrome/browser/extensions/extension_tabs_module_constants.h +++ b/chrome/browser/extensions/extension_tabs_module_constants.h @@ -36,6 +36,7 @@ extern const wchar_t kTopKey[]; extern const wchar_t kUrlKey[]; extern const wchar_t kWidthKey[]; extern const wchar_t kWindowIdKey[]; +extern const wchar_t kIncognitoKey[]; // Value consts. extern const char kStatusValueComplete[]; diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc index ac0a2eb..48323d4 100644 --- a/chrome/browser/extensions/extension_test_api.cc +++ b/chrome/browser/extensions/extension_test_api.cc @@ -2,10 +2,12 @@ // 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_test_api.h" + +#include "chrome/browser/browser.h" #include "chrome/browser/profile.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/extensions/extensions_quota_service.h" -#include "chrome/browser/extensions/extension_test_api.h" #include "chrome/common/notification_service.h" bool ExtensionTestPassFunction::RunImpl() { @@ -41,3 +43,10 @@ bool ExtensionTestQuotaResetFunction::RunImpl() { quota->violators_.clear(); return true; } + +bool ExtensionTestCreateIncognitoTabFunction::RunImpl() { + std::string url; + EXTENSION_FUNCTION_VALIDATE(args_->GetAsString(&url)); + Browser::OpenURLOffTheRecord(profile(), GURL(url)); + return true; +} diff --git a/chrome/browser/extensions/extension_test_api.h b/chrome/browser/extensions/extension_test_api.h index 3b89e53..ee62627 100644 --- a/chrome/browser/extensions/extension_test_api.h +++ b/chrome/browser/extensions/extension_test_api.h @@ -31,4 +31,10 @@ class ExtensionTestQuotaResetFunction : public SyncExtensionFunction { DECLARE_EXTENSION_FUNCTION_NAME("test.resetQuota") }; +class ExtensionTestCreateIncognitoTabFunction : public SyncExtensionFunction { + ~ExtensionTestCreateIncognitoTabFunction() {} + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("test.createIncognitoTab") +}; + #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_ diff --git a/chrome/browser/extensions/extension_toolstrip_api.cc b/chrome/browser/extensions/extension_toolstrip_api.cc index 18d1839..56ad0a2 100644 --- a/chrome/browser/extensions/extension_toolstrip_api.cc +++ b/chrome/browser/extensions/extension_toolstrip_api.cc @@ -40,7 +40,7 @@ bool ToolstripFunction::RunImpl() { error_ = kNotAToolstripError; return false; } - Browser* browser = dispatcher()->GetBrowser(); + Browser* browser = GetBrowser(); if (!browser) { error_ = kNotAToolstripError; return false; @@ -133,8 +133,8 @@ void ToolstripEventRouter::DispatchEvent(Profile *profile, std::string json_args; base::JSONWriter::Write(&json, false, &json_args); std::string full_event_name = StringPrintf(event_name, routing_id); - profile->GetExtensionMessageService()-> - DispatchEventToRenderers(full_event_name, json_args); + profile->GetExtensionMessageService()->DispatchEventToRenderers( + full_event_name, json_args, profile->IsOffTheRecord()); } } diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc index 4bffb44..f1bd648 100644 --- a/chrome/browser/extensions/extension_ui_unittest.cc +++ b/chrome/browser/extensions/extension_ui_unittest.cc @@ -50,8 +50,8 @@ namespace { // Produce test output. scoped_ptr<DictionaryValue> actual_output_data( - ExtensionsDOMHandler::CreateExtensionDetailValue(&extension, pages, - true)); + ExtensionsDOMHandler::CreateExtensionDetailValue(NULL, &extension, + pages, true)); // Compare the outputs. return expected_output_data->Equals(actual_output_data.get()); diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc index 8192968..5537dc4 100644 --- a/chrome/browser/extensions/extension_uitest.cc +++ b/chrome/browser/extensions/extension_uitest.cc @@ -218,8 +218,10 @@ public: tab_dict.SetInteger(extension_tabs_module_constants::kIndexKey, 1); tab_dict.SetInteger(extension_tabs_module_constants::kWindowIdKey, 1); tab_dict.SetBoolean(extension_tabs_module_constants::kSelectedKey, true); + tab_dict.SetBoolean(extension_tabs_module_constants::kIncognitoKey, + false); tab_dict.SetString(extension_tabs_module_constants::kUrlKey, - "http://www.google.com"); + "http://www.google.com"); std::string tab_json; base::JSONWriter::Write(&tab_dict, false, &tab_json); @@ -327,7 +329,7 @@ class ExtensionTestBrowserEvents : public ExtensionUITest { const char* ExtensionTestBrowserEvents::events_[] = { // Window events. "[\"windows.onCreated\", \"[{'id':42,'focused':true,'top':0,'left':0," - "'width':100,'height':100}]\"]", + "'width':100,'height':100,'incognito':false}]\"]", "[\"windows.onRemoved\", \"[42]\"]", @@ -335,11 +337,11 @@ const char* ExtensionTestBrowserEvents::events_[] = { // Tab events. "[\"tabs.onCreated\", \"[{'id':42,'index':1,'windowId':1," - "'selected':true,'url':'http://www.google.com'}]\"]", + "'selected':true,'url':'http://www.google.com','incognito':false}]\"]", "[\"tabs.onUpdated\", \"[42, {'status': 'complete'," "'url':'http://www.google.com'}, {'id':42,'index':1,'windowId':1," - "'selected':true,'url':'http://www.google.com'}]\"]", + "'selected':true,'url':'http://www.google.com','incognito':false}]\"]", "[\"tabs.onMoved\", \"[42, {'windowId':1,'fromIndex':1,'toIndex':2}]\"]", diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index d171767..9cf2fb9 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -530,13 +530,19 @@ base::Time ExtensionsService::LastPingDay(const std::string& extension_id) { } bool ExtensionsService::IsIncognitoEnabled(const std::string& extension_id) { - Extension* extension = GetExtensionById(extension_id, true); - if (!extension) - return false; + return extension_prefs_->IsIncognitoEnabled(extension_id); +} + +void ExtensionsService::SetIsIncognitoEnabled(const std::string& extension_id, + bool enabled) { + Extension* extension = GetExtensionByIdInternal(extension_id, true, true); + extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled); - return extension_prefs_->IsIncognitoEnabled(extension_id) && - extension->HasApiPermission(Extension::kExperimentalPermission) && - extension->HasApiPermission(Extension::kIncognitoPermission); + std::pair<Extension*, bool> details(extension, enabled); + NotificationService::current()->Notify( + NotificationType::EXTENSION_INCOGNITO_CHANGED, + Source<Profile>(profile_), + Details<std::pair<Extension*, bool> >(&details)); } void ExtensionsService::CheckForExternalUpdates() { diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 078ac01..a95d0aa 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -106,10 +106,9 @@ class ExtensionsService const base::Time& time); virtual base::Time LastPingDay(const std::string& extension_id); - // Returns true if this extension can run in an incognito window. The - // decision is based on both user consent and the extension having the right - // permission. + // Whether this extension can run in an incognito window. bool IsIncognitoEnabled(const std::string& extension_id); + void SetIsIncognitoEnabled(const std::string& extension_id, bool enabled); const FilePath& install_directory() const { return install_directory_; } diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 24dc43e..4201c17 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -31,6 +31,7 @@ #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_reporter.h" @@ -100,6 +101,12 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path, l10n_util::GetString(IDS_EXTENSIONS_DISABLE)); localized_strings.SetString(L"enable", l10n_util::GetString(IDS_EXTENSIONS_ENABLE)); + localized_strings.SetString(L"disableIncognito", + l10n_util::GetString(IDS_EXTENSIONS_DISABLE_INCOGNITO)); + localized_strings.SetString(L"enableIncognito", + l10n_util::GetString(IDS_EXTENSIONS_ENABLE_INCOGNITO)); + localized_strings.SetString(L"enableIncognitoWarning", + l10n_util::GetString(IDS_EXTENSIONS_ENABLE_INCOGNITO_WARNING)); localized_strings.SetString(L"reload", l10n_util::GetString(IDS_EXTENSIONS_RELOAD)); localized_strings.SetString(L"uninstall", @@ -251,6 +258,8 @@ void ExtensionsDOMHandler::RegisterMessages() { NewCallback(this, &ExtensionsDOMHandler::HandleReloadMessage)); dom_ui_->RegisterMessageCallback("enable", NewCallback(this, &ExtensionsDOMHandler::HandleEnableMessage)); + dom_ui_->RegisterMessageCallback("enableIncognito", + NewCallback(this, &ExtensionsDOMHandler::HandleEnableIncognitoMessage)); dom_ui_->RegisterMessageCallback("uninstall", NewCallback(this, &ExtensionsDOMHandler::HandleUninstallMessage)); dom_ui_->RegisterMessageCallback("options", @@ -284,6 +293,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) { // themes. if (!(*extension)->IsTheme()) { extensions_list->Append(CreateExtensionDetailValue( + extensions_service_.get(), *extension, GetActivePagesForExtension((*extension)->id()), true)); extension_icons->push_back(PickExtensionIcon(*extension)); } @@ -293,6 +303,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) { extension != extensions->end(); ++extension) { if (!(*extension)->IsTheme()) { extensions_list->Append(CreateExtensionDetailValue( + extensions_service_.get(), *extension, GetActivePagesForExtension((*extension)->id()), false)); extension_icons->push_back(PickExtensionIcon(*extension)); } @@ -303,6 +314,10 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) { ->GetBoolean(prefs::kExtensionsUIDeveloperMode); results->SetBoolean(L"developerMode", developer_mode); + results->SetBoolean(L"experimentalIncognito", + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExperimentalExtensionApis)); + if (icon_loader_.get()) icon_loader_->Cancel(); @@ -402,6 +417,17 @@ void ExtensionsDOMHandler::HandleEnableMessage(const Value* value) { } } +void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const Value* value) { + CHECK(value->IsType(Value::TYPE_LIST)); + const ListValue* list = static_cast<const ListValue*>(value); + CHECK(list->GetSize() == 2); + std::string extension_id, enable_str; + CHECK(list->GetString(0, &extension_id)); + CHECK(list->GetString(1, &enable_str)); + extensions_service_->SetIsIncognitoEnabled(extension_id, + (enable_str == "true")); +} + void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) { CHECK(value->IsType(Value::TYPE_LIST)); const ListValue* list = static_cast<const ListValue*>(value); @@ -657,8 +683,8 @@ DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue( // Static DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue( - const Extension *extension, const std::vector<ExtensionPage>& pages, - bool enabled) { + ExtensionsService* service, const Extension *extension, + const std::vector<ExtensionPage>& pages, bool enabled) { DictionaryValue* extension_data = new DictionaryValue(); extension_data->SetString(L"id", extension->id()); @@ -666,6 +692,10 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue( extension_data->SetString(L"description", extension->description()); extension_data->SetString(L"version", extension->version()->GetString()); extension_data->SetBoolean(L"enabled", enabled); + extension_data->SetBoolean(L"enabledIncognito", + service ? service->IsIncognitoEnabled(extension->id()) : false); + extension_data->SetBoolean(L"incognitoSafe", + extension->HasApiPermission(Extension::kIncognitoPermission)); extension_data->SetBoolean(L"allow_reload", extension->location() == Extension::LOAD); diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h index cabc5be..decdc64 100644 --- a/chrome/browser/extensions/extensions_ui.h +++ b/chrome/browser/extensions/extensions_ui.h @@ -106,9 +106,11 @@ class ExtensionsDOMHandler virtual void RegisterMessages(); // Extension Detail JSON Struct for page. (static for ease of testing). + // Note: service can be NULL in unit tests. static DictionaryValue* CreateExtensionDetailValue( - const Extension *extension, - const std::vector<ExtensionPage>&, + ExtensionsService* service, + const Extension* extension, + const std::vector<ExtensionPage>& pages, bool enabled); // ContentScript JSON Struct for page. (static for ease of testing). @@ -143,6 +145,9 @@ class ExtensionsDOMHandler // Callback for "enable" message. void HandleEnableMessage(const Value* value); + // Callback for "enableIncognito" message. + void HandleEnableIncognitoMessage(const Value* value); + // Callback for "uninstall" message. void HandleUninstallMessage(const Value* value); diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc index a7d69f6..9506efd 100644 --- a/chrome/browser/extensions/user_script_master.cc +++ b/chrome/browser/extensions/user_script_master.cc @@ -294,6 +294,8 @@ UserScriptMaster::UserScriptMaster(const FilePath& script_dir, Profile* profile) Source<Profile>(profile_)); registrar_.Add(this, NotificationType::EXTENSION_LOADED, Source<Profile>(profile_)); + registrar_.Add(this, NotificationType::EXTENSION_INCOGNITO_CHANGED, + Source<Profile>(profile_)); registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, Source<Profile>(profile_)); } @@ -348,6 +350,22 @@ void UserScriptMaster::Observe(NotificationType type, StartScan(); break; } + case NotificationType::EXTENSION_INCOGNITO_CHANGED: { + // Toggle the incognito_enabled bit for any content scripts inside the + // extension. + Extension* extension = + Details<std::pair<Extension*, bool> >(details).ptr()->first; + bool incognito_enabled = + Details<std::pair<Extension*, bool> >(details).ptr()->second; + for (UserScriptList::iterator iter = lone_scripts_.begin(); + iter != lone_scripts_.end(); ++iter) { + if (iter->extension_id() == extension->id()) + (*iter).set_incognito_enabled(incognito_enabled); + } + if (extensions_service_ready_) + StartScan(); + break; + } case NotificationType::EXTENSION_UNLOADED: { // Remove any content scripts. @@ -378,14 +396,3 @@ void UserScriptMaster::StartScan() { script_reloader_->StartScan(user_script_dir_, lone_scripts_); } - -void UserScriptMaster::ReloadExtensionForTesting(Extension* extension) { - bool incognito_enabled = profile_->GetExtensionsService()-> - IsIncognitoEnabled(extension->id()); - for (UserScriptList::iterator iter = lone_scripts_.begin(); - iter != lone_scripts_.end(); ++iter) { - if (iter->extension_id() == extension->id()) - (*iter).set_incognito_enabled(incognito_enabled); - } - StartScan(); -} diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h index 19562f0..cc0b437 100644 --- a/chrome/browser/extensions/user_script_master.h +++ b/chrome/browser/extensions/user_script_master.h @@ -47,11 +47,6 @@ class UserScriptMaster : public base::RefCountedThreadSafe<UserScriptMaster>, // Returns the path to the directory user scripts are stored in. FilePath user_script_dir() const { return user_script_dir_; } - // Note: this is only for testing. This will reload the scripts associated - // with the given extension. This is only temporary until we get better - // machinery in place for toggling incognito-enabled extensions. - void ReloadExtensionForTesting(Extension* extension); - protected: friend class base::RefCountedThreadSafe<UserScriptMaster>; |