diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-03 17:57:44 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-03 17:57:44 +0000 |
commit | c2e74fe834afaeed3bf8d21034bb995437518843 (patch) | |
tree | c9b3876a00bbbb78984b619246a4069ded4c1664 | |
parent | 3f7116cf4b4e725cc43c7331fed6cd1a1b03bc96 (diff) | |
download | chromium_src-c2e74fe834afaeed3bf8d21034bb995437518843.zip chromium_src-c2e74fe834afaeed3bf8d21034bb995437518843.tar.gz chromium_src-c2e74fe834afaeed3bf8d21034bb995437518843.tar.bz2 |
Revert "Revert "Allow DOMUI pages to call window.open(), giving DOMUI privileges to the new""
Second attempt at r25250. The tests were broken in Release mode due to a race. Should be fixed.
BUG=17636
Review URL: http://codereview.chromium.org/172120
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25329 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 236 insertions, 93 deletions
diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc index f776baa..cdfbd7f 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.cc +++ b/chrome/browser/dom_ui/dom_ui_factory.cc @@ -18,102 +18,83 @@ #include "chrome/common/url_constants.h" #include "googleurl/src/gurl.h" -// Backend for both querying for and creating new DOMUI objects. If you're just -// querying whether there's a DOM UI for the given URL, pass NULL for both the -// web contents and the new_ui. The return value will indiacate whether a DOM UI -// exists for the given URL. -// -// If you want to create a DOM UI, pass non-NULL pointers for both tab_contents -// and new_ui. The *new_ui pointer will be filled with the created UI if it -// succeeds (indicated by a return value of true). The caller owns the *new_ui -// pointer. -static bool CreateDOMUI(const GURL& url, TabContents* tab_contents, - DOMUI** new_ui) { +const DOMUITypeID DOMUIFactory::kNoDOMUI = NULL; + +// A function for creating a new DOMUI. The caller owns the return value, which +// may be NULL (for example, if the URL refers to an non-existent extension). +typedef DOMUI* (*DOMUIFactoryFunction)(TabContents* tab_contents, + const GURL& url); + +// Template for defining DOMUIFactoryFunction. +template<class T> +DOMUI* NewDOMUI(TabContents* contents, const GURL& url) { + return new T(contents); +} + +// Special case for extensions. +template<> +DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) { + // Don't use a DOMUI for non-existent extensions. + ExtensionsService* service = contents->profile()->GetExtensionsService(); + bool valid_extension = (service && service->GetExtensionById(url.host())); + if (valid_extension) + return new ExtensionDOMUI(contents); + return NULL; +} + +// Returns a function that can be used to create the right type of DOMUI for a +// tab, based on its URL. Returns NULL if the URL doesn't have DOMUI associated +// with it. Even if the factory function is valid, it may yield a NULL DOMUI +// when invoked for a particular tab - see NewDOMUI<ExtensionDOMUI>. +static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) { // Currently, any gears: URL means an HTML dialog. - if (url.SchemeIs(chrome::kGearsScheme)) { - if (new_ui) - *new_ui = new HtmlDialogUI(tab_contents); - return true; - } - - if (url.SchemeIs(chrome::kExtensionScheme)) { - // We assume we have a valid extension unless we have a TabContents which - // can prove us wrong. This can can happen if the user types in a URL - // manually. - bool valid_extension = true; - if (tab_contents) { - // TabContents can be NULL if we're doing a quick UseDOMUIForURL check. - ExtensionsService* service = - tab_contents->profile()->GetExtensionsService(); - valid_extension = (service && service->GetExtensionById(url.host())); - } - if (valid_extension) { - if (new_ui) - *new_ui = new ExtensionDOMUI(tab_contents); - return true; - } - return false; - } + if (url.SchemeIs(chrome::kGearsScheme)) + return &NewDOMUI<HtmlDialogUI>; + + if (url.SchemeIs(chrome::kExtensionScheme)) + return &NewDOMUI<ExtensionDOMUI>; // TODO(mhm) Make sure this ifdef is removed once print is complete. #if !defined(GOOGLE_CHROME_BUILD) - if (url.SchemeIs(chrome::kPrintScheme)) { - if (new_ui) - *new_ui = new PrintUI(tab_contents); - return true; - } + if (url.SchemeIs(chrome::kPrintScheme)) + return &NewDOMUI<PrintUI>; #endif // This will get called a lot to check all URLs, so do a quick check of other // schemes (gears was handled above) to filter out most URLs. if (!url.SchemeIs(chrome::kChromeInternalScheme) && !url.SchemeIs(chrome::kChromeUIScheme)) - return false; + return NULL; - if (url.host() == chrome::kSyncResourcesHost) { - if (new_ui) - *new_ui = new HtmlDialogUI(tab_contents); - return true; - } + if (url.host() == chrome::kSyncResourcesHost) + return &NewDOMUI<HtmlDialogUI>; // Special case the new tab page. In older versions of Chrome, the new tab // page was hosted at chrome-internal:<blah>. This might be in people's saved // sessions or bookmarks, so we say any URL with that scheme triggers the new // tab page. if (url.host() == chrome::kChromeUINewTabHost || - url.SchemeIs(chrome::kChromeInternalScheme)) { - if (new_ui) - *new_ui = new NewTabUI(tab_contents); - return true; - } + url.SchemeIs(chrome::kChromeInternalScheme)) + return &NewDOMUI<NewTabUI>; // We must compare hosts only since some of the DOM UIs append extra stuff // after the host name. - if (url.host() == chrome::kChromeUIHistoryHost) { - if (new_ui) - *new_ui = new HistoryUI(tab_contents); - return true; - } - - if (url.host() == chrome::kChromeUIDownloadsHost) { - if (new_ui) - *new_ui = new DownloadsUI(tab_contents); - return true; - } - - if (url.host() == chrome::kChromeUIExtensionsHost) { - if (new_ui) - *new_ui = new ExtensionsUI(tab_contents); - return true; - } - - if (url.host() == chrome::kChromeUIDevToolsHost) { - if (new_ui) - *new_ui = new DevToolsUI(tab_contents); - return true; - } + if (url.host() == chrome::kChromeUIHistoryHost) + return &NewDOMUI<HistoryUI>; + if (url.host() == chrome::kChromeUIDownloadsHost) + return &NewDOMUI<DownloadsUI>; + if (url.host() == chrome::kChromeUIExtensionsHost) + return &NewDOMUI<ExtensionsUI>; + if (url.host() == chrome::kChromeUIDevToolsHost) + return &NewDOMUI<DevToolsUI>; + + return NULL; +} - return false; +// static +DOMUITypeID DOMUIFactory::GetDOMUIType(const GURL& url) { + DOMUIFactoryFunction function = GetDOMUIFactoryFunction(url); + return function ? reinterpret_cast<DOMUITypeID>(function) : kNoDOMUI; } // static @@ -126,16 +107,16 @@ bool DOMUIFactory::HasDOMUIScheme(const GURL& url) { // static bool DOMUIFactory::UseDOMUIForURL(const GURL& url) { - return CreateDOMUI(url, NULL, NULL); + return GetDOMUIFactoryFunction(url) != NULL; } // static DOMUI* DOMUIFactory::CreateDOMUIForURL(TabContents* tab_contents, const GURL& url) { - DOMUI* dom_ui; - if (!CreateDOMUI(url, tab_contents, &dom_ui)) + DOMUIFactoryFunction function = GetDOMUIFactoryFunction(url); + if (!function) return NULL; - return dom_ui; + return (*function)(tab_contents, url); } // static diff --git a/chrome/browser/dom_ui/dom_ui_factory.h b/chrome/browser/dom_ui/dom_ui_factory.h index e4e36c3..db1500c 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.h +++ b/chrome/browser/dom_ui/dom_ui_factory.h @@ -11,8 +11,21 @@ class DOMUI; class GURL; class TabContents; +// An opaque identifier used to identify a DOMUI. This can only be compared to +// kNoDOMUI or other DOMUI types. See GetDOMUIType. +typedef void* DOMUITypeID; + class DOMUIFactory { public: + // A special DOMUI type that signifies that a given page would not use the + // DOM UI system. + static const DOMUITypeID kNoDOMUI; + + // Returns a type identifier indicating what DOMUI we would use for the + // given URL. This is useful for comparing the potential DOMUIs for two URLs. + // Returns kNoDOMUI if the given URL will not use the DOM UI system. + static DOMUITypeID GetDOMUIType(const GURL& url); + // Returns true if the given URL's scheme would trigger the DOM UI system. // This is a less precise test than UseDONUIForURL, which tells you whether // that specific URL matches a known one. This one is faster and can be used diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc index b2efa99..db4a670 100644 --- a/chrome/browser/extensions/extension_browsertests_misc.cc +++ b/chrome/browser/extensions/extension_browsertests_misc.cc @@ -501,3 +501,77 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UninstallDisabled) { EXPECT_EQ(0u, service->extensions()->size()); EXPECT_EQ(0u, service->disabled_extensions()->size()); } + +// Helper function for common code shared by the 3 WindowOpen tests below. +static TabContents* WindowOpenHelper(Browser* browser, const GURL& start_url, + const std::string& newtab_url) { + ui_test_utils::NavigateToURL(browser, start_url); + + bool result = false; + ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser->GetSelectedTabContents()->render_view_host(), L"", + L"window.open('" + UTF8ToWide(newtab_url) + L"');" + L"window.domAutomationController.send(true);", &result); + EXPECT_TRUE(result); + + // Now the current tab should be the new tab. + TabContents* newtab = browser->GetSelectedTabContents(); + GURL expected_url = start_url.Resolve(newtab_url); + if (newtab->GetURL() != expected_url) { + ui_test_utils::WaitForNavigation( + &browser->GetSelectedTabContents()->controller()); + } + EXPECT_EQ(newtab->GetURL(), expected_url); + + return newtab; +} + +// Tests that an extension page can call window.open to an extension URL and +// the new window has extension privileges. +IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenExtension) { + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); + + TabContents* newtab = WindowOpenHelper( + browser(), + GURL("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.html"), + "newtab.html"); + + bool result = false; + ui_test_utils::ExecuteJavaScriptAndExtractBool( + newtab->render_view_host(), L"", L"testExtensionApi()", &result); + EXPECT_TRUE(result); +} + +// Tests that if an extension page calls window.open to an invalid extension +// URL, the browser doesn't crash. +IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenInvalidExtension) { + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); + + WindowOpenHelper( + browser(), + GURL("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.html"), + "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab/newtab.html"); + + // If we got to this point, we didn't crash, so we're good. +} + +// Tests that calling window.open from the newtab page to an extension URL +// does not give the new window extension privileges - because the opening page +// does not have extension privileges. +IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) { + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("uitest").AppendASCII("window_open"))); + + TabContents* newtab = WindowOpenHelper( + browser(), + GURL("about:blank"), + "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/newtab.html"); + + // Extension API should fail. + bool result = false; + ui_test_utils::ExecuteJavaScriptAndExtractBool( + newtab->render_view_host(), L"", L"testExtensionApi()", &result); + EXPECT_FALSE(result); +} diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc index 044a28a..c3741c7 100644 --- a/chrome/browser/extensions/extension_dom_ui.cc +++ b/chrome/browser/extensions/extension_dom_ui.cc @@ -40,7 +40,7 @@ void ExtensionDOMUI::ResetExtensionFunctionDispatcher( // Use the NavigationController to get the URL rather than the TabContents // since this is the real underlying URL (see HandleChromeURLOverride). NavigationController& controller = tab_contents()->controller(); - const GURL& url = controller.pending_entry()->url(); + const GURL& url = controller.GetActiveEntry()->url(); extension_function_dispatcher_.reset( new ExtensionFunctionDispatcher(render_view_host, this, url)); } diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 60aa0d3..8690e6a 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -232,7 +232,7 @@ void ExtensionHost::CreateNewWindow(int route_id, base::WaitableEvent* modal_dialog_event) { delegate_view_helper_.CreateNewWindow( route_id, modal_dialog_event, render_view_host()->process()->profile(), - site_instance()); + site_instance(), DOMUIFactory::GetDOMUIType(url_)); } void ExtensionHost::CreateNewWidget(int route_id, bool activatable) { diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 41cbd00..95a53dd 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1609,7 +1609,9 @@ void RenderViewHost::OnExtensionRequest(const std::string& name, bool has_callback) { if (!ChildProcessSecurityPolicy::GetInstance()-> HasExtensionBindings(process()->id())) { - NOTREACHED() << "Blocked unauthorized use of extension bindings."; + // This can happen if someone uses window.open() to open an extension URL + // from a non-extension context. + BlockExtensionRequest(request_id); return; } @@ -1623,6 +1625,11 @@ void RenderViewHost::SendExtensionResponse(int request_id, bool success, response, error)); } +void RenderViewHost::BlockExtensionRequest(int request_id) { + SendExtensionResponse(request_id, false, "", + "Access to extension API denied."); +} + void RenderViewHost::OnExtensionPostMessage( int port_id, const std::string& message) { if (process()->profile()->GetExtensionMessageService()) { diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 6381ef1..0fe33e8 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -418,11 +418,15 @@ class RenderViewHost : public RenderWidgetHost, // Creates a new RenderWidget with the given route id. void CreateNewWidget(int route_id, bool activatable); - // Senf the response to an extension api call. + // Send the response to an extension api call. void SendExtensionResponse(int request_id, bool success, const std::string& response, const std::string& error); + // Send a response to an extension api call that it was blocked for lack of + // permission. + void BlockExtensionRequest(int request_id); + void SignalModalDialogEvent(); void ResetModalDialogEvent(); diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc index 184fc5e..2f0eef8 100644 --- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc +++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc @@ -21,7 +21,7 @@ void RenderViewHostDelegateViewHelper::CreateNewWindow(int route_id, base::WaitableEvent* modal_dialog_event, Profile* profile, - SiteInstance* site) { + SiteInstance* site, DOMUITypeID domui_type) { // Create the new web contents. This will automatically create the new // TabContentsView. In the future, we may want to create the view separately. TabContents* new_contents = @@ -29,6 +29,7 @@ void RenderViewHostDelegateViewHelper::CreateNewWindow(int route_id, site, route_id, modal_dialog_event); + new_contents->set_opener_dom_ui_type(domui_type); TabContentsView* new_view = new_contents->view(); // TODO(brettw) it seems bogus that we have to call this function on the diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.h b/chrome/browser/tab_contents/render_view_host_delegate_helper.h index 4f9e600..215cddcc 100644 --- a/chrome/browser/tab_contents/render_view_host_delegate_helper.h +++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/gfx/rect.h" #include "base/waitable_event.h" +#include "chrome/browser/dom_ui/dom_ui_factory.h" #include "webkit/glue/webpreferences.h" #include "webkit/glue/window_open_disposition.h" @@ -31,7 +32,8 @@ class RenderViewHostDelegateViewHelper { virtual void CreateNewWindow(int route_id, base::WaitableEvent* modal_dialog_event, - Profile* profile, SiteInstance* site); + Profile* profile, SiteInstance* site, + DOMUITypeID domui_type); virtual RenderWidgetHostView* CreateNewWidget(int route_id, bool activatable, RenderProcessHost* process); virtual TabContents* GetCreatedWindow(int route_id); diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc index 101c1f8..6b3866f 100644 --- a/chrome/browser/tab_contents/render_view_host_manager.cc +++ b/chrome/browser/tab_contents/render_view_host_manager.cc @@ -187,6 +187,11 @@ void RenderViewHostManager::DidNavigateMainFrame( } } +void RenderViewHostManager::SetDOMUIPostCommit(DOMUI* dom_ui) { + DCHECK(!dom_ui_.get()); + dom_ui_.reset(dom_ui); +} + void RenderViewHostManager::RendererAbortedProvisionalLoad( RenderViewHost* render_view_host) { // We used to cancel the pending renderer here for cross-site downloads. diff --git a/chrome/browser/tab_contents/render_view_host_manager.h b/chrome/browser/tab_contents/render_view_host_manager.h index 8c8dde2..c562628 100644 --- a/chrome/browser/tab_contents/render_view_host_manager.h +++ b/chrome/browser/tab_contents/render_view_host_manager.h @@ -127,6 +127,11 @@ class RenderViewHostManager // Called when a renderer's main frame navigates. void DidNavigateMainFrame(RenderViewHost* render_view_host); + // Set the DOMUI after committing a page load. This is useful for navigations + // initiated from a renderer, where we want to give the new renderer DOMUI + // privileges from the originating renderer. + void SetDOMUIPostCommit(DOMUI* dom_ui); + // Called when a provisional load on the given renderer is aborted. void RendererAbortedProvisionalLoad(RenderViewHost* render_view_host); diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 00d313a..083296c 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -260,7 +260,8 @@ TabContents::TabContents(Profile* profile, message_box_active_(CreateEvent(NULL, TRUE, FALSE, NULL)), #endif last_javascript_message_dismissal_(), - suppress_javascript_messages_(false) { + suppress_javascript_messages_(false), + opener_dom_ui_type_(DOMUIFactory::kNoDOMUI) { pending_install_.page_id = 0; pending_install_.callback_functor = NULL; @@ -1273,6 +1274,21 @@ DOMUI* TabContents::GetDOMUIForCurrentState() { void TabContents::DidNavigateMainFramePostCommit( const NavigationController::LoadCommittedDetails& details, const ViewHostMsg_FrameNavigate_Params& params) { + if (opener_dom_ui_type_ != DOMUIFactory::kNoDOMUI) { + // If this is a window.open navigation, use the same DOMUI as the renderer + // that opened the window, as long as both renderers have the same + // privileges. + if (opener_dom_ui_type_ == DOMUIFactory::GetDOMUIType(GetURL())) { + DOMUI* dom_ui = DOMUIFactory::CreateDOMUIForURL(this, GetURL()); + // dom_ui might be NULL if the URL refers to a non-existent extension. + if (dom_ui) { + render_manager_.SetDOMUIPostCommit(dom_ui); + dom_ui->RenderViewCreated(render_view_host()); + } + } + opener_dom_ui_type_ = DOMUIFactory::kNoDOMUI; + } + if (details.is_user_initiated_main_frame_load()) { // Clear the status bubble. This is a workaround for a bug where WebKit // doesn't let us know that the cursor left an element during a @@ -2113,10 +2129,9 @@ void TabContents::ProcessDOMUIMessage(const std::string& message, int request_id, bool has_callback) { if (!render_manager_.dom_ui()) { - // We shouldn't get a DOM UI message when we haven't enabled the DOM UI. - // Because the renderer might be owned and sending random messages, we need - // to ignore these inproper ones. - NOTREACHED(); + // This can happen if someone uses window.open() to open an extension URL + // from a non-extension context. + render_view_host()->BlockExtensionRequest(request_id); return; } render_manager_.dom_ui()->ProcessDOMUIMessage(message, content, request_id, diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 2935273..51b8954 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -18,6 +18,7 @@ #include "base/scoped_ptr.h" #include "chrome/browser/autocomplete/autocomplete_edit.h" #include "chrome/browser/cancelable_request.h" +#include "chrome/browser/dom_ui/dom_ui_factory.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/fav_icon_helper.h" #include "chrome/browser/find_notification_details.h" @@ -590,6 +591,10 @@ class TabContents : public PageNavigator, return &renderer_preferences_; } + void set_opener_dom_ui_type(DOMUITypeID opener_dom_ui_type) { + opener_dom_ui_type_ = opener_dom_ui_type; + } + private: friend class NavigationController; // Used to access the child_windows_ (ConstrainedWindowList) for testing @@ -1112,6 +1117,10 @@ class TabContents : public PageNavigator, // Settings that get passed to the renderer process. RendererPreferences renderer_preferences_; + // If this tab was created from a renderer using window.open, this will be + // non-NULL and represent the DOMUI of the opening renderer. + DOMUITypeID opener_dom_ui_type_; + // --------------------------------------------------------------------------- DISALLOW_COPY_AND_ASSIGN(TabContents); diff --git a/chrome/browser/tab_contents/tab_contents_view.cc b/chrome/browser/tab_contents/tab_contents_view.cc index 78d084a..ecdf697 100644 --- a/chrome/browser/tab_contents/tab_contents_view.cc +++ b/chrome/browser/tab_contents/tab_contents_view.cc @@ -32,9 +32,10 @@ void TabContentsView::UpdatePreferredWidth(int pref_width) { void TabContentsView::CreateNewWindow(int route_id, base::WaitableEvent* modal_dialog_event) { - delegate_view_helper_.CreateNewWindow(route_id, modal_dialog_event, - tab_contents_->profile(), - tab_contents_->GetSiteInstance()); + delegate_view_helper_.CreateNewWindow( + route_id, modal_dialog_event, + tab_contents_->profile(), tab_contents_->GetSiteInstance(), + DOMUIFactory::GetDOMUIType(tab_contents_->GetURL())); } void TabContentsView::CreateNewWidget(int route_id, bool activatable) { diff --git a/chrome/test/data/extensions/uitest/window_open/manifest.json b/chrome/test/data/extensions/uitest/window_open/manifest.json new file mode 100644 index 0000000..bcdc692 --- /dev/null +++ b/chrome/test/data/extensions/uitest/window_open/manifest.json @@ -0,0 +1,6 @@ +{ + "version": "1.0.0.0", + "name": "window.open test", + "description": "An extension for an extension UITest.", + "permissions": ["tabs"] +} diff --git a/chrome/test/data/extensions/uitest/window_open/newtab.html b/chrome/test/data/extensions/uitest/window_open/newtab.html new file mode 100644 index 0000000..8fb5b96 --- /dev/null +++ b/chrome/test/data/extensions/uitest/window_open/newtab.html @@ -0,0 +1,12 @@ +<script> +function testExtensionApi() { + try { + chrome.tabs.getAllInWindow(null, function() { + window.domAutomationController.send( + !chrome.extension.lastError); + }); + } catch (e) { + window.domAutomationController.send(false); + } +} +</script> diff --git a/chrome/test/data/extensions/uitest/window_open/test.html b/chrome/test/data/extensions/uitest/window_open/test.html new file mode 100644 index 0000000..c267f19 --- /dev/null +++ b/chrome/test/data/extensions/uitest/window_open/test.html @@ -0,0 +1,8 @@ +HOWDIE!!! + +<script> +function testWindowOpen(url) { + window.open(url); + window.domAutomationController.send(true); +} +</script> |