diff options
-rw-r--r-- | chrome/browser/browser_focus_uitest.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_browser_tests.cc | 771 | ||||
-rw-r--r-- | chrome/browser/tab_contents/navigation_entry.h | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 3 | ||||
-rw-r--r-- | chrome/browser/views/find_bar_win_browsertest.cc | 15 | ||||
-rw-r--r-- | chrome/test/data/ssl/google.html | 2 | ||||
-rw-r--r-- | chrome/test/ui_test_utils.cc | 117 | ||||
-rw-r--r-- | chrome/test/ui_test_utils.h | 61 |
8 files changed, 899 insertions, 88 deletions
diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc index 4d46a59..c9f8052 100644 --- a/chrome/browser/browser_focus_uitest.cc +++ b/chrome/browser/browser_focus_uitest.cc @@ -264,11 +264,12 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) { // Now let's press tab to move the focus. for (int j = 0; j < 7; ++j) { // Let's make sure the focus is on the expected element in the page. - ui_test_utils::JavaScriptRunner js_runner( + std::string actual; + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetSelectedTabContents()->AsWebContents(), L"", - L"window.domAutomationController.send(getFocusedElement());"); - std::string actual = js_runner.Run(); + L"window.domAutomationController.send(getFocusedElement());", + &actual)); ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); ui_controls::SendKeyPressNotifyWhenDone(L'\t', false, false, false, @@ -300,11 +301,12 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) { ::Sleep(kActionDelayMs); // Let's make sure the focus is on the expected element in the page. - ui_test_utils::JavaScriptRunner js_runner( + std::string actual; + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetSelectedTabContents()->AsWebContents(), L"", - L"window.domAutomationController.send(getFocusedElement());"); - std::string actual = js_runner.Run(); + L"window.domAutomationController.send(getFocusedElement());", + &actual)); ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str()); } diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index c2a49c4..5b513d2 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc @@ -2,19 +2,774 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/base/ssl_test_util.h" - +#include "chrome/browser/browser.h" +#include "chrome/browser/tab_contents/interstitial_page.h" +#include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/web_contents.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" #include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" + +const wchar_t kDocRoot[] = L"chrome/test/data"; + +class SSLUITest : public InProcessBrowserTest { + public: + SSLUITest() { + EnableDOMAutomation(); + } + + scoped_refptr<HTTPTestServer> PlainServer() { + return HTTPTestServer::CreateServer(kDocRoot, NULL); + } + + scoped_refptr<HTTPSTestServer> GoodCertServer() { + return HTTPSTestServer::CreateGoodServer(kDocRoot); + } + + scoped_refptr<HTTPSTestServer> BadCertServer() { + return HTTPSTestServer::CreateExpiredServer(kDocRoot); + } -namespace { + void CheckAuthenticatedState(TabContents* tab, + bool mixed_content, + bool unsafe_content) { + NavigationEntry* entry = tab->controller().GetActiveEntry(); + ASSERT_TRUE(entry); + EXPECT_EQ(NavigationEntry::NORMAL_PAGE, entry->page_type()); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, entry->ssl().security_style()); + EXPECT_EQ(0, entry->ssl().cert_status() & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(mixed_content, entry->ssl().has_mixed_content()); + EXPECT_EQ(unsafe_content, entry->ssl().has_unsafe_content()); + } -const wchar_t* const kDocRoot = L"chrome/test/data"; + void CheckUnauthenticatedState(TabContents* tab) { + NavigationEntry* entry = tab->controller().GetActiveEntry(); + ASSERT_TRUE(entry); + EXPECT_EQ(NavigationEntry::NORMAL_PAGE, entry->page_type()); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, entry->ssl().security_style()); + EXPECT_EQ(0, entry->ssl().cert_status() & net::CERT_STATUS_ALL_ERRORS); + EXPECT_FALSE(entry->ssl().has_mixed_content()); + EXPECT_FALSE(entry->ssl().has_unsafe_content()); + } -class SSLBrowserTest : public InProcessBrowserTest { + void CheckAuthenticationBrokenState(TabContents* tab, + int error, + bool interstitial) { + NavigationEntry* entry = tab->controller().GetActiveEntry(); + ASSERT_TRUE(entry); + EXPECT_EQ(interstitial ? NavigationEntry::INTERSTITIAL_PAGE : + NavigationEntry::NORMAL_PAGE, + entry->page_type()); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, + entry->ssl().security_style()); + EXPECT_EQ(error, entry->ssl().cert_status() & net::CERT_STATUS_ALL_ERRORS); + EXPECT_FALSE(entry->ssl().has_mixed_content()); + EXPECT_FALSE(entry->ssl().has_unsafe_content()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(SSLUITest); }; -} // namespace +// Visits a regular page over http. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTP) { + scoped_refptr<HTTPTestServer> server = PlainServer(); + + ui_test_utils::NavigateToURL(browser(), + server->TestServerPageW(L"files/ssl/google.html")); + + CheckUnauthenticatedState(browser()->GetSelectedTabContents()); +} + +// Visits a page over http which includes broken https resources (status should +// be OK). +// TODO(jcampan): test that bad HTTPS content is blocked (otherwise we'll give +// the secure cookies away!). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPWithBrokenHTTPSResource) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + ui_test_utils::NavigateToURL(browser(), http_server->TestServerPageW( + L"files/ssl/page_with_unsafe_contents.html")); + + CheckUnauthenticatedState(browser()->GetSelectedTabContents()); +} + +// Visits a page over OK https: +IN_PROC_BROWSER_TEST_F(SSLUITest, TestOKHTTPS) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + + ui_test_utils::NavigateToURL(browser(), + https_server->TestServerPageW(L"files/ssl/google.html")); + + CheckAuthenticatedState(browser()->GetSelectedTabContents(), + false, false); // No mixed/unsafe content. +} + +// Visits a page with https error and proceed: +IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSExpiredCertAndProceed) { + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + ui_test_utils::NavigateToURL(browser(), + bad_https_server->TestServerPageW(L"files/ssl/google.html")); + + TabContents* tab = browser()->GetSelectedTabContents(); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + true); // Interstitial showing + + // Proceed through the interstitial. + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); -// TODO(jcampan): port SSLUITest to SSLBrowserTest. -IN_PROC_BROWSER_TEST_F(SSLBrowserTest, TestHTTP) { + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + false); // No interstitial showing } + +// Visits a page with https error and don't proceed (and ensure we can still +// navigate at that point): +IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSExpiredCertAndDontProceed) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + // First navigate to an OK page. + ui_test_utils::NavigateToURL(browser(), good_https_server->TestServerPageW( + L"files/ssl/google.html")); + + TabContents* tab = browser()->GetSelectedTabContents(); + NavigationEntry* entry = tab->controller().GetActiveEntry(); + ASSERT_TRUE(entry); + + GURL cross_site_url = + bad_https_server->TestServerPageW(L"files/ssl/google.html"); + // Change the host name from 127.0.0.1 to localhost so it triggers a + // cross-site navigation so we can test http://crbug.com/5800 is gone. + ASSERT_EQ("127.0.0.1", cross_site_url.host()); + GURL::Replacements replacements; + std::string new_host("localhost"); + replacements.SetHostStr(new_host); + cross_site_url = cross_site_url.ReplaceComponents(replacements); + + // Now go to a bad HTTPS page. + ui_test_utils::NavigateToURL(browser(), cross_site_url); + + // An interstitial should be showing. + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, + true); // Interstitial showing. + + // Simulate user clicking "Take me back". + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->DontProceed(); + + // We should be back to the original good page. + CheckAuthenticatedState(tab, false, false); + + // Try to navigate to a new page. (to make sure bug 5800 is fixed). + ui_test_utils::NavigateToURL(browser(), + http_server->TestServerPageW(L"files/ssl/google.html")); + CheckUnauthenticatedState(tab); +} + +// +// Mixed contents +// + +// Visits a page with mixed content. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestMixedContents) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + + // Load a page with mixed-content, the default behavior is to show the mixed + // content. + ui_test_utils::NavigateToURL(browser(), https_server->TestServerPageW( + L"files/ssl/page_with_mixed_contents.html")); + + CheckAuthenticatedState(browser()->GetSelectedTabContents(), + true /* mixed-content */, false); +} + +// Visits a page with mixed content. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestMixedContentsFilterAll) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + + // Set the "block mixed-content" preference. + browser()->profile()->GetPrefs()->SetInteger(prefs::kMixedContentFiltering, + FilterPolicy::FILTER_ALL); + + // Load a page with mixed-content, the mixed content shouldn't load. + ui_test_utils::NavigateToURL(browser(), https_server->TestServerPageW( + L"files/ssl/page_with_mixed_contents.html")); + + TabContents* tab = browser()->GetSelectedTabContents(); + NavigationEntry* entry = tab->controller().GetActiveEntry(); + ASSERT_TRUE(entry); + EXPECT_EQ(NavigationEntry::NORMAL_PAGE, entry->page_type()); + + // The image should be filtered. + int img_width = 0; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt( + tab, L"", L"window.domAutomationController.send(ImageWidth());", + &img_width)); + // In order to check that the image was not loaded, we check its width. + // The actual image (Google logo) is 114 pixels wide, we assume the broken + // image is less than 100. + EXPECT_GT(100, img_width); + + // The state should be OK since we are not showing the resource. + CheckAuthenticatedState(tab, false, false); + + // There should be one info-bar to show the mixed-content. + EXPECT_EQ(1, tab->infobar_delegate_count()); + + // Activate the link on the info-bar to show the mixed-content. + InfoBarDelegate* delegate = tab->GetInfoBarDelegateAt(0); + ASSERT_TRUE(delegate->AsConfirmInfoBarDelegate()); + delegate->AsConfirmInfoBarDelegate()->Accept(); + // Showing the mixed-contents triggered a page reload, let's wait for it to + // finish. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + // The image should show now. + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt( + tab, L"", L"window.domAutomationController.send(ImageWidth());", + &img_width)); + EXPECT_LT(100, img_width); + + // And our status should be mixed-content. + CheckAuthenticatedState(tab, true /* mixed-content */, false); +} + +// Visits a page with an http script that tries to suppress our mixed content +// warnings by randomize location.hash. +// Based on http://crbug.com/8706 +IN_PROC_BROWSER_TEST_F(SSLUITest, TestMixedContentsRandomizeHash) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + + ui_test_utils::NavigateToURL(browser(), https_server->TestServerPageW( + L"files/ssl/page_with_http_script.html")); + + CheckAuthenticatedState(browser()->GetSelectedTabContents(), + true /* mixed-content */, false); +} + +// Visits a page with unsafe content and make sure that: +// - frames content is replaced with warning +// - images and scripts are filtered out entirely +IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnsafeContents) { + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + ui_test_utils::NavigateToURL(browser(), good_https_server->TestServerPageW( + L"files/ssl/page_with_unsafe_contents.html")); + + TabContents* tab = browser()->GetSelectedTabContents(); + // When the bad content is filtered, the state is expected to be + // authenticated. + CheckAuthenticatedState(tab, false, false); + + // Because of cross-frame scripting restrictions, we cannot access the iframe + // content. So to know if the frame was loaded, we just check if a popup was + // opened (the iframe content opens one). + // Note: because of bug 1115868, no constrained window is opened right now. + // Once the bug is fixed, this will do the real check. + EXPECT_EQ(0, tab->constrained_window_count()); + + int img_width; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt( + tab, L"", L"window.domAutomationController.send(ImageWidth());", + &img_width)); + // In order to check that the image was not loaded, we check its width. + // The actual image (Google logo) is 114 pixels wide, we assume the broken + // image is less than 100. + EXPECT_GT(100, img_width); + + bool js_result = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + tab, L"", L"window.domAutomationController.send(IsFooSet());", + &js_result)); + EXPECT_FALSE(js_result); +} + +// Visits a page with mixed content loaded by JS (after the initial page load). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestMixedContentsLoadedFromJS) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + + ui_test_utils::NavigateToURL(browser(), https_server->TestServerPageW( + L"files/ssl/page_with_dynamic_mixed_contents.html")); + + TabContents* tab = browser()->GetSelectedTabContents(); + CheckAuthenticatedState(tab, false, false); + + // Load the insecure image. + bool js_result = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + tab, L"", L"loadBadImage();", &js_result)); + EXPECT_TRUE(js_result); + + // We should now have mixed-contents. + CheckAuthenticatedState(tab, true /* mixed-content */, false); +} + +// Visits two pages from the same origin: one with mixed content and one +// without. The test checks that we propagate the mixed content state from one +// to the other. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestMixedContentsTwoTabs) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + + ui_test_utils::NavigateToURL(browser(), + https_server->TestServerPageW(L"files/ssl/blank_page.html")); + + TabContents* tab1 = browser()->GetSelectedTabContents(); + + // This tab should be fine. + CheckAuthenticatedState(tab1, false, false); + + // Create a new tab. + GURL url = + https_server->TestServerPageW(L"files/ssl/page_with_http_script.html"); + TabContents* tab2 = browser()->AddTabWithURL(url, + GURL(), + PageTransition::TYPED, true, 0, + NULL); + ui_test_utils::WaitForNavigation(&(tab2->controller())); + + // The new tab has mixed content. + CheckAuthenticatedState(tab2, true /* mixed-content */, false); + + // Which means the origin for the first tab has also been contaminated with + // mixed content. + CheckAuthenticatedState(tab1, true /* mixed-content */, false); +} + +// Visits a page with an image over http. Visits another page over https +// referencing that same image over http (hoping it is coming from the webcore +// memory cache). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestCachedMixedContents) { + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + + ui_test_utils::NavigateToURL(browser(), http_server->TestServerPageW( + L"files/ssl/page_with_mixed_contents.html")); + TabContents* tab = browser()->GetSelectedTabContents(); + CheckUnauthenticatedState(tab); + + // Load again but over SSL. It should have mixed-contents (even though the + // image comes from the WebCore memory cache). + ui_test_utils::NavigateToURL(browser(), https_server->TestServerPageW( + L"files/ssl/page_with_mixed_contents.html")); + CheckAuthenticatedState(tab, true /* mixed-content */, false); +} + +// This test ensures the CN invalid status does not 'stick' to a certificate +// (see bug #1044942) and that it depends on the host-name. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestCNInvalidStickiness) { + const std::string kLocalHost = "localhost"; + scoped_refptr<HTTPSTestServer> https_server = + HTTPSTestServer::CreateMismatchedServer(kDocRoot); + ASSERT_TRUE(NULL != https_server.get()); + + // First we hit the server with hostname, this generates an invalid policy + // error. + ui_test_utils::NavigateToURL(browser(), + https_server->TestServerPageW(L"files/ssl/google.html")); + + // We get an interstitial page as a result. + TabContents* tab = browser()->GetSelectedTabContents(); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, + true); // Interstitial showing. + + // We proceed through the interstitial page. + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, + false); // No interstitial showing. + + // Now we try again with the right host name this time. + + // Let's change the host-name in the url. + GURL url = https_server->TestServerPageW(L"files/ssl/google.html"); + std::string::size_type hostname_index = url.spec().find(kLocalHost); + ASSERT_TRUE(hostname_index != std::string::npos); // Test sanity check. + std::string new_url; + new_url.append(url.spec().substr(0, hostname_index)); + new_url.append(net::TestServerLauncher::kHostName); + new_url.append(url.spec().substr(hostname_index + kLocalHost.size())); + + ui_test_utils::NavigateToURL(browser(), GURL(new_url)); + + // Security state should be OK. + CheckAuthenticatedState(tab, false, false); + + // Now try again the broken one to make sure it is still broken. + ui_test_utils::NavigateToURL(browser(), + https_server->TestServerPageW(L"files/ssl/google.html")); + + // Since we OKed the interstitial last time, we get right to the page. + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID, + false); // No interstitial showing. +} + +// Test that navigating to a #ref does not change a bad security state. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestRefNavigation) { + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + ui_test_utils::NavigateToURL(browser(), + bad_https_server->TestServerPageW(L"files/ssl/page_with_refs.html")); + + TabContents* tab = browser()->GetSelectedTabContents(); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + true); // Interstitial showing. + + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + false); // No interstitial showing. + + // Now navigate to a ref in the page, the security state should not have + // changed. + ui_test_utils::NavigateToURL(browser(), + bad_https_server->TestServerPageW(L"files/ssl/page_with_refs.html#jp")); + + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + false); // No interstitial showing. +} + +// Tests that closing a page that has a unsafe pop-up does not crash the browser +// (bug #1966). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestCloseTabWithUnsafePopup) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + ui_test_utils::NavigateToURL(browser(), http_server->TestServerPageW( + L"files/ssl/page_with_unsafe_popup.html")); + + TabContents* tab1 = browser()->GetSelectedTabContents(); + // It is probably overkill to add a notification for a popup-opening, let's + // just poll. + for (int i = 0; i < 10; i++) { + if (tab1->constrained_window_count() > 0) + break; + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask(), 1000); + ui_test_utils::RunMessageLoop(); + } + ASSERT_EQ(1, tab1->constrained_window_count()); + + // Let's add another tab to make sure the browser does not exit when we close + // the first tab. + GURL url = http_server->TestServerPageW(L"files/ssl/google.html"); + TabContents* tab2 = browser()->AddTabWithURL(url, + GURL(), + PageTransition::TYPED, + true, 0, NULL); + ui_test_utils::WaitForNavigation(&(tab2->controller())); + + // Close the first tab. + browser()->CloseTabContents(tab1); +} + +// Visit a page over bad https that is a redirect to a page with good https. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectBadToGoodHTTPS) { + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + GURL url1 = bad_https_server->TestServerPageW(L"server-redirect?"); + GURL url2 = good_https_server->TestServerPageW(L"files/ssl/google.html"); + + ui_test_utils::NavigateToURL(browser(), GURL(url1.spec() + url2.spec())); + + TabContents* tab = browser()->GetSelectedTabContents(); + + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + true); // Interstitial showing. + + // We proceed through the interstitial page. + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + // We have been redirected to the good page. + CheckAuthenticatedState(tab, false, false); // No mixed/unsafe content. +} + +// Visit a page over good https that is a redirect to a page with bad https. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectGoodToBadHTTPS) { + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + GURL url1 = good_https_server->TestServerPageW(L"server-redirect?"); + GURL url2 = bad_https_server->TestServerPageW(L"files/ssl/google.html"); + ui_test_utils::NavigateToURL(browser(), GURL(url1.spec() + url2.spec())); + + TabContents* tab = browser()->GetSelectedTabContents(); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + true); // Interstitial showing. + + // We proceed through the interstitial page. + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + false); // No interstitial showing. +} + +// Visit a page over http that is a redirect to a page with good HTTPS. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectHTTPToGoodHTTPS) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + + TabContents* tab = browser()->GetSelectedTabContents(); + + // HTTP redirects to good HTTPS. + GURL http_url = http_server->TestServerPageW(L"server-redirect?"); + GURL good_https_url = + good_https_server->TestServerPageW(L"files/ssl/google.html"); + + ui_test_utils::NavigateToURL(browser(), + GURL(http_url.spec() + good_https_url.spec())); + CheckAuthenticatedState(tab, false, false); // No mixed/unsafe content. +} + +// Visit a page over http that is a redirect to a page with bad HTTPS. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectHTTPToBadHTTPS) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + TabContents* tab = browser()->GetSelectedTabContents(); + + GURL http_url = http_server->TestServerPageW(L"server-redirect?"); + GURL bad_https_url = + bad_https_server->TestServerPageW(L"files/ssl/google.html"); + ui_test_utils::NavigateToURL(browser(), + GURL(http_url.spec() + bad_https_url.spec())); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + true); // Interstitial showing. + + // Continue on the interstitial. + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + false); // No interstitial showing. +} + +// Visit a page over https that is a redirect to a page with http (to make sure +// we don't keep the secure state). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectHTTPSToHTTP) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> https_server = GoodCertServer(); + + GURL https_url = https_server->TestServerPageW(L"server-redirect?"); + GURL http_url = http_server->TestServerPageW(L"files/ssl/google.html"); + + ui_test_utils::NavigateToURL(browser(), + GURL(https_url.spec() + http_url.spec())); + CheckUnauthenticatedState(browser()->GetSelectedTabContents()); +} + +// Visits a page to which we could not connect (bad port) over http and https +// and make sure the security style is correct. +IN_PROC_BROWSER_TEST_F(SSLUITest, TestConnectToBadPort) { + ui_test_utils::NavigateToURL(browser(), GURL("http://localhost:17")); + CheckUnauthenticatedState(browser()->GetSelectedTabContents()); + + // Same thing over HTTPS. + ui_test_utils::NavigateToURL(browser(), GURL("https://localhost:17")); + CheckUnauthenticatedState(browser()->GetSelectedTabContents()); +} + +// +// Frame navigation +// + +// From a good HTTPS top frame: +// - navigate to an OK HTTPS frame +// - navigate to a bad HTTPS (expect unsafe content and filtered frame), then +// back +// - navigate to HTTP (expect mixed content), then back +IN_PROC_BROWSER_TEST_F(SSLUITest, TestGoodFrameNavigation) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + TabContents* tab = browser()->GetSelectedTabContents(); + ui_test_utils::NavigateToURL( + browser(), + good_https_server->TestServerPageW(L"files/ssl/top_frame.html")); + + CheckAuthenticatedState(tab, false, false); + + bool success = false; + // Now navigate inside the frame. + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + L"", + L"window.domAutomationController.send(clickLink('goodHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + ui_test_utils::WaitForNavigation(&tab->controller()); + + // We should still be fine. + CheckAuthenticatedState(tab, false, false); + + // Now let's hit a bad page. + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + L"", + L"window.domAutomationController.send(clickLink('badHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + ui_test_utils::WaitForNavigation(&tab->controller()); + + // The security style should still be secure. + CheckAuthenticatedState(tab, false, false); + + // And the frame should be blocked. + bool is_content_evil = true; + std::wstring content_frame_xpath(L"html/frameset/frame[2]"); + std::wstring is_frame_evil_js( + L"window.domAutomationController" + L".send(document.getElementById('evilDiv') != null);"); + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + content_frame_xpath, + is_frame_evil_js, + &is_content_evil)); + EXPECT_FALSE(is_content_evil); + + // Now go back, our state should still be OK. + tab->controller().GoBack(); + ui_test_utils::WaitForNavigation(&tab->controller()); + CheckAuthenticatedState(tab, false, false); + + // Navigate to a page served over HTTP. + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + L"", + L"window.domAutomationController.send(clickLink('HTTPLink'));", + &success)); + EXPECT_TRUE(success); + ui_test_utils::WaitForNavigation(&tab->controller()); + + // Our state should be mixed-content. + CheckAuthenticatedState(tab, true, false); + + // Go back, our state should be unchanged. + tab->controller().GoBack(); + ui_test_utils::WaitForNavigation(&tab->controller()); + CheckAuthenticatedState(tab, true, false); +} + +// From a bad HTTPS top frame: +// - navigate to an OK HTTPS frame (expected to be still authentication broken). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestBadFrameNavigation) { + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + TabContents* tab = browser()->GetSelectedTabContents(); + ui_test_utils::NavigateToURL( + browser(), + bad_https_server->TestServerPageW(L"files/ssl/top_frame.html")); + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, + true); // Interstitial showing + + // Continue on the interstitial. + InterstitialPage* interstitial_page = tab->interstitial_page(); + ASSERT_TRUE(interstitial_page); + interstitial_page->Proceed(); + // Wait for the navigation to be done. + ui_test_utils::WaitForNavigation(&(tab->controller())); + + // Navigate to a good frame. + bool success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + L"", + L"window.domAutomationController.send(clickLink('goodHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + ui_test_utils::WaitForNavigation(&tab->controller()); + + // We should still be authentication broken. + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false); +} + +// From an HTTP top frame, navigate to good and bad HTTPS (security state should +// stay unauthenticated). +IN_PROC_BROWSER_TEST_F(SSLUITest, TestUnauthenticatedFrameNavigation) { + scoped_refptr<HTTPTestServer> http_server = PlainServer(); + scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer(); + scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer(); + + TabContents* tab = browser()->GetSelectedTabContents(); + ui_test_utils::NavigateToURL( + browser(), + http_server->TestServerPageW(L"files/ssl/top_frame.html")); + CheckUnauthenticatedState(tab); + + // Now navigate inside the frame to a secure HTTPS frame. + bool success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + L"", + L"window.domAutomationController.send(clickLink('goodHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + ui_test_utils::WaitForNavigation(&tab->controller()); + + // We should still be unauthenticated. + CheckUnauthenticatedState(tab); + + // Now navigate to a bad HTTPS frame. + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + L"", + L"window.domAutomationController.send(clickLink('badHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + ui_test_utils::WaitForNavigation(&tab->controller()); + + // State should not have changed. + CheckUnauthenticatedState(tab); + + // And the frame should have been blocked (see bug #2316). + bool is_content_evil = true; + std::wstring content_frame_xpath(L"html/frameset/frame[2]"); + std::wstring is_frame_evil_js( + L"window.domAutomationController" + L".send(document.getElementById('evilDiv') != null);"); + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(tab, + content_frame_xpath, is_frame_evil_js, &is_content_evil)); + EXPECT_FALSE(is_content_evil); +} + +// TODO(jcampan): more tests to do below. + +// Visit a page over https that contains a frame with a redirect. + +// XMLHttpRequest mixed in synchronous mode. + +// XMLHttpRequest mixed in asynchronous mode. + +// XMLHttpRequest over bad ssl in synchronous mode. + +// XMLHttpRequest over OK ssl in synchronous mode. diff --git a/chrome/browser/tab_contents/navigation_entry.h b/chrome/browser/tab_contents/navigation_entry.h index 677e633..964a724 100644 --- a/chrome/browser/tab_contents/navigation_entry.h +++ b/chrome/browser/tab_contents/navigation_entry.h @@ -100,7 +100,7 @@ class NavigationEntry { // Raw accessors for all the content status flags. This contains a // combination of any of the ContentStatusFlags defined above. It is used - // by the UI tests for checking and for certain copying. Use the per-status + // by some tests for checking and for certain copying. Use the per-status // functions for normal usage. void set_content_status(int content_status) { content_status_ = content_status; @@ -120,7 +120,7 @@ class NavigationEntry { // Copy and assignment is explicitly allowed for this class. }; - // The type of the page an entry corresponds to. Used by ui tests. + // The type of the page an entry corresponds to. Used by tests. enum PageType { NORMAL_PAGE = 0, ERROR_PAGE, diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 6a8b83f..181aafb 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -358,6 +358,9 @@ class TabContents : public PageNavigator, // Called when the blocked popup notification is shown or hidden. virtual void PopupNotificationVisibilityChanged(bool visible); + // Returns the number of constrained windows in this tab. Used by tests. + size_t constrained_window_count() { return child_windows_.size(); } + // Views and focus ----------------------------------------------------------- // TODO(brettw): Most of these should be removed and the caller should call // the view directly. diff --git a/chrome/browser/views/find_bar_win_browsertest.cc b/chrome/browser/views/find_bar_win_browsertest.cc index 4cca160..744560a 100644 --- a/chrome/browser/views/find_bar_win_browsertest.cc +++ b/chrome/browser/views/find_bar_win_browsertest.cc @@ -149,11 +149,13 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageFrames) { } std::string FocusedOnPage(WebContents* web_contents) { - ui_test_utils::JavaScriptRunner js_runner( + std::string result; + ui_test_utils::ExecuteJavaScriptAndExtractString( web_contents, L"", - L"window.domAutomationController.send(getFocusedElement());"); - return js_runner.Run(); + L"window.domAutomationController.send(getFocusedElement());", + &result); + return result; } // This tests the FindInPage end-state, in other words: what is focused when you @@ -186,11 +188,12 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageEndState) { EXPECT_EQ(1, FindInPage(L"Google", FWD, IGNORE_CASE, false)); // Move the selection to link 1, after searching. - ui_test_utils::JavaScriptRunner js_runner( + std::string result; + ui_test_utils::ExecuteJavaScriptAndExtractString( web_contents, L"", - L"window.domAutomationController.send(selectLink1());"); - js_runner.Run(); + L"window.domAutomationController.send(selectLink1());", + &result); // End the find session. web_contents->StopFinding(false); diff --git a/chrome/test/data/ssl/google.html b/chrome/test/data/ssl/google.html index 3ef1ca1..ac08534 100644 --- a/chrome/test/data/ssl/google.html +++ b/chrome/test/data/ssl/google.html @@ -1,4 +1,4 @@ <html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Google</title><style>body,td,a,p,.h{font-family:arial,sans-serif}.h{font-size:20px}.h{color:#3366cc}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}#gbar{float:left;font-weight:bold;height:22px;padding-left:2px}.gbh,.gb2 div{border-top:1px solid #c9d7f1;font-size:0;height:0}.gbh{position:absolute;top:24px;width:100%}.gb2 div{margin:5px}#gbi{background:#fff;border:1px solid;border-color:#c9d7f1 #36c #36c #a2bae7;font-size:13px;top:24px;z-index:1000}#guser{padding-bottom:7px !important}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.73em;vertical-align:top}.gb2 a{display:block;padding:.2em .5em}}#gbi,.gb2{display:none;position:absolute;width:8em}.gb2{z-index:1001}#gbar a,#gbar a:active,#gbar a:visited{color:#00c;font-weight:normal}.gb2 a,.gb3 a{text-decoration:none}#gbar .gb2 a:hover{background:#36c;color:#fff;display:block}</style><script>window.google={kEI:"BuG9R7b_PI6SoASYhdTtDQ",kEXPI:"17259,17735,17870",kHL:"en"}; function sf(){document.f.q.focus()} window.rwt=function(b,d,e,g,h,f,i){var a=encodeURIComponent||escape,c=b.href.split("#");b.href="/url?sa=t"+(d?"&oi="+a(d):"")+(e?"&cad="+a(e):"")+"&ct="+a(g)+"&cd="+a(h)+"&url="+a(c[0]).replace(/\+/g,"%2B")+"&ei=BuG9R7b_PI6SoASYhdTtDQ"+(f?"&usg="+f:"")+i+(c[1]?"#"+c[1]:"");b.onmousedown="";return true}; -window.gbar={};(function(){var a=window.gbar,b,g,h;function l(c,f,e){c.display=h?"none":"block";c.left=f+"px";c.top=e+"px"}a.tg=function(c){var f=0,e=0,d,m=0,n,j=window.navExtra,k,i=document;g=g||i.getElementById("gbar").getElementsByTagName("span");(c||window.event).cancelBubble=!m;if(!b){b=i.createElement(Array.every||window.createPopup?"iframe":"DIV");b.frameBorder="0";b.scrolling="no";b.src="#";g[7].parentNode.appendChild(b).id="gbi";if(j&&g[7])for(n in j){k=i.createElement("span");k.appendChild(j[n]);g[7].parentNode.insertBefore(k,g[7]).className="gb2"}i.onclick=a.close}while(d=g[++m]){if(e){l(d.style,e+1,f+25);f+=d.firstChild.tagName=="DIV"?9:20}if(d.className=="gb3"){do e+=d.offsetLeft;while(d=d.offsetParent)}}b.style.height=f+"px";l(b.style,e,24);h=!h};a.close=function(c){h&&a.tg(c)}})();</script></head><body onload="sf();if(document.images){new Image().src='/images/nav_logo3.png'}" topmargin="3" alink="#ff0000" bgcolor="#ffffff" link="#0000cc" marginheight="3" text="#000000" vlink="#551a8b"><div id="gbar"><nobr><span class="gb1">Web</span> <span class="gb1"><a href="http://images.google.com/imghp?hl=en&tab=wi">Images</a></span> <span class="gb1"><a href="http://maps.google.com/maps?hl=en&tab=wl">Maps</a></span> <span class="gb1"><a href="http://news.google.com/nwshp?hl=en&tab=wn">News</a></span> <span class="gb1"><a href="http://www.google.com/prdhp?hl=en&tab=wf">Shopping</a></span> <span class="gb1"><a href="http://mail.google.com/mail/?hl=en&tab=wm">Gmail</a></span> <span class="gb3"><a href="http://www.google.com/intl/en/options/" onclick="this.blur();gbar.tg(event);return !1"><u>more</u> <small>▼</small></a></span> <span class="gb2"><a href="http://video.google.com/?hl=en&tab=wv">Video</a></span> <span class="gb2"><a href="http://groups.google.com/grphp?hl=en&tab=wg">Groups</a></span> <span class="gb2"><a href="http://books.google.com/bkshp?hl=en&tab=wp">Books</a></span> <span class="gb2"><a href="http://scholar.google.com/schhp?hl=en&tab=ws">Scholar</a></span> <span class="gb2"><a href="http://finance.google.com/finance?hl=en&tab=we">Finance</a></span> <span class="gb2"><a href="http://blogsearch.google.com/?hl=en&tab=wb">Blogs</a></span> <span class="gb2"><div></div></span> <span class="gb2"><a href="http://www.youtube.com/?hl=en&tab=w1">YouTube</a></span> <span class="gb2"><a href="http://www.google.com/calendar/render?hl=en&tab=wc">Calendar</a></span> <span class="gb2"><a href="http://picasaweb.google.com/home?hl=en&tab=wq">Photos</a></span> <span class="gb2"><a href="http://docs.google.com/?hl=en&tab=wo">Documents</a></span> <span class="gb2"><a href="http://www.google.com/reader/view/?hl=en&tab=wy">Reader</a></span> <span class="gb2"><div></div></span> <span class="gb2"><a href="http://www.google.com/intl/en/options/">even more »</a></span> </nobr></div><div class="gbh" style="left: 0pt;"></div><div class="gbh" style="right: 0pt;"></div><div id="guser" style="padding: 0pt 0pt 4px; font-size: 84%;" width="100%" align="right"><nobr><b>jcampan@gmail.com</b> | <a href="http://www.google.com/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a> | <a href="https://www.google.com/accounts/ManageAccount">My Account</a> | <a href="http://www.google.com/accounts/Logout?continue=http://www.google.com/">Sign out</a></nobr></div><center><br id="lgpd" clear="all"><img alt="Google" src="google_files/logo.gif" height="110" width="276"><br><br><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tbody><tr valign="top"><td width="25%"> </td><td align="center" nowrap="nowrap"><input name="hl" value="en" type="hidden"><input maxlength="2048" name="q" size="55" title="Google Search" value=""><br><input name="btnG" value="Google Search" type="submit"><input name="btnI" value="I'm Feeling Lucky" type="submit"></td><td nowrap="nowrap" width="25%"><font size="-2"> <a href="http://www.google.com/advanced_search?hl=en">Advanced Search</a><br> <a href="http://www.google.com/preferences?hl=en">Preferences</a><br> <a href="http://www.google.com/language_tools?hl=en">Language Tools</a></font></td></tr></tbody></table></form><br><br><font size="-1"><a href="http://www.google.com/intl/en/ads/">Advertising Programs</a> - <a href="http://www.google.com/services/">Business Solutions</a> - <a href="http://www.google.com/intl/en/about.html">About Google</a></font><p><font size="-2">©2008 Google</font></p></center></body></html>
\ No newline at end of file +window.gbar={};(function(){var a=window.gbar,b,g,h;function l(c,f,e){c.display=h?"none":"block";c.left=f+"px";c.top=e+"px"}a.tg=function(c){var f=0,e=0,d,m=0,n,j=window.navExtra,k,i=document;g=g||i.getElementById("gbar").getElementsByTagName("span");(c||window.event).cancelBubble=!m;if(!b){b=i.createElement(Array.every||window.createPopup?"iframe":"DIV");b.frameBorder="0";b.scrolling="no";b.src="#";g[7].parentNode.appendChild(b).id="gbi";if(j&&g[7])for(n in j){k=i.createElement("span");k.appendChild(j[n]);g[7].parentNode.insertBefore(k,g[7]).className="gb2"}i.onclick=a.close}while(d=g[++m]){if(e){l(d.style,e+1,f+25);f+=d.firstChild.tagName=="DIV"?9:20}if(d.className=="gb3"){do e+=d.offsetLeft;while(d=d.offsetParent)}}b.style.height=f+"px";l(b.style,e,24);h=!h};a.close=function(c){h&&a.tg(c)}})();</script></head><body onload="sf();if(document.images){new Image().src='/images/nav_logo3.png'}" topmargin="3" alink="#ff0000" bgcolor="#ffffff" link="#0000cc" marginheight="3" text="#000000" vlink="#551a8b"><div id="gbar"><nobr><span class="gb1">Web</span> <span class="gb1"><a href="imghp?hl=en&tab=wi">Images</a></span> <span class="gb1"><a href="maps?hl=en&tab=wl">Maps</a></span> <span class="gb1"><a href="nwshp?hl=en&tab=wn">News</a></span> <span class="gb1"><a href="prdhp?hl=en&tab=wf">Shopping</a></span> <span class="gb1"><a href="mail/?hl=en&tab=wm">Gmail</a></span> <span class="gb3"><a href="intl/en/options/" onclick="this.blur();gbar.tg(event);return !1"><u>more</u> <small>▼</small></a></span> <span class="gb2"><a href="?hl=en&tab=wv">Video</a></span> <span class="gb2"><a href="grphp?hl=en&tab=wg">Groups</a></span> <span class="gb2"><a href="bkshp?hl=en&tab=wp">Books</a></span> <span class="gb2"><a href="schhp?hl=en&tab=ws">Scholar</a></span> <span class="gb2"><a href="finance?hl=en&tab=we">Finance</a></span> <span class="gb2"><a href="?hl=en&tab=wb">Blogs</a></span> <span class="gb2"><div></div></span> <span class="gb2"><a href="?hl=en&tab=w1">YouTube</a></span> <span class="gb2"><a href="calendar/render?hl=en&tab=wc">Calendar</a></span> <span class="gb2"><a href="home?hl=en&tab=wq">Photos</a></span> <span class="gb2"><a href="?hl=en&tab=wo">Documents</a></span> <span class="gb2"><a href="reader/view/?hl=en&tab=wy">Reader</a></span> <span class="gb2"><div></div></span> <span class="gb2"><a href="intl/en/options/">even more »</a></span> </nobr></div><div class="gbh" style="left: 0pt;"></div><div class="gbh" style="right: 0pt;"></div><div id="guser" style="padding: 0pt 0pt 4px; font-size: 84%;" width="100%" align="right"><nobr><b>jcampan@gmail.com</b> | <a href="url?sa=p&pref=ig&pval=3&q=ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a> | <a href="https://www.google.com/accounts/ManageAccount">My Account</a> | <a href="accounts/Logout?continue=">Sign out</a></nobr></div><center><br id="lgpd" clear="all"><img alt="Google" src="google_files/logo.gif" height="110" width="276"><br><br><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tbody><tr valign="top"><td width="25%"> </td><td align="center" nowrap="nowrap"><input name="hl" value="en" type="hidden"><input maxlength="2048" name="q" size="55" title="Google Search" value=""><br><input name="btnG" value="Google Search" type="submit"><input name="btnI" value="I'm Feeling Lucky" type="submit"></td><td nowrap="nowrap" width="25%"><font size="-2"> <a href="advanced_search?hl=en">Advanced Search</a><br> <a href="preferences?hl=en">Preferences</a><br> <a href="language_tools?hl=en">Language Tools</a></font></td></tr></tbody></table></form><br><br><font size="-1"><a href="intl/en/ads/">Advertising Programs</a> - <a href="services/">Business Solutions</a> - <a href="intl/en/about.html">About Google</a></font><p><font size="-2">©2008 Google</font></p></center></body></html> diff --git a/chrome/test/ui_test_utils.cc b/chrome/test/ui_test_utils.cc index bd8ff59..6d9094b 100644 --- a/chrome/test/ui_test_utils.cc +++ b/chrome/test/ui_test_utils.cc @@ -4,11 +4,12 @@ #include "chrome/test/ui_test_utils.h" +#include "base/json_reader.h" #include "base/message_loop.h" #include "chrome/browser/browser.h" #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/tab_contents/navigation_controller.h" -#include "chrome/browser/tab_contents/web_contents.h" +#include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" #include "chrome/views/widget/accelerator_handler.h" @@ -65,6 +66,32 @@ class NavigationNotificationObserver : public NotificationObserver { DISALLOW_COPY_AND_ASSIGN(NavigationNotificationObserver); }; +class DOMOperationObserver : public NotificationObserver { + public: + explicit DOMOperationObserver(TabContents* tab_contents) { + registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE, + Source<TabContents>(tab_contents)); + RunMessageLoop(); + } + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::DOM_OPERATION_RESPONSE); + Details<DomOperationNotificationDetails> dom_op_details(details); + response_ = dom_op_details->json(); + MessageLoopForUI::current()->Quit(); + } + + std::string response() const { return response_; } + + private: + NotificationRegistrar registrar_; + std::string response_; + + DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver); +}; + } // namespace void RunMessageLoop() { @@ -98,42 +125,68 @@ void NavigateToURLBlockUntilNavigationsComplete(Browser* browser, WaitForNavigations(controller, number_of_navigations); } -JavaScriptRunner::JavaScriptRunner(WebContents* web_contents, - const std::wstring& frame_xpath, - const std::wstring& jscript) - : web_contents_(web_contents), - frame_xpath_(frame_xpath), - jscript_(jscript) { - NotificationService::current()-> - AddObserver(this, NotificationType::DOM_OPERATION_RESPONSE, - Source<WebContents>(web_contents)); +Value* ExecuteJavaScript(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& original_script) { + // TODO(jcampan): we should make the domAutomationController not require an + // automation id. + std::wstring script = L"window.domAutomationController.setAutomationId(0);" + + original_script; + tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(frame_xpath, + script); + DOMOperationObserver dom_op_observer(tab_contents); + std::string json = dom_op_observer.response(); + // Wrap |json| in an array before deserializing because valid JSON has an + // array or an object as the root. + json.insert(0, "["); + json.append("]"); + + scoped_ptr<Value> root_val(JSONReader::Read(json, true)); + if (!root_val->IsType(Value::TYPE_LIST)) + return NULL; + + ListValue* list = static_cast<ListValue*>(root_val.get()); + Value* result; + if (!list || !list->GetSize() || + !list->Remove(0, &result)) // Remove gives us ownership of the value. + return NULL; + + return result; } -void JavaScriptRunner::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - Details<DomOperationNotificationDetails> dom_op_details(details); - result_ = dom_op_details->json(); - // The Jasonified response has quotes, remove them. - if (result_.length() > 1 && result_[0] == '"') - result_ = result_.substr(1, result_.length() - 2); - - NotificationService::current()-> - RemoveObserver(this, NotificationType::DOM_OPERATION_RESPONSE, - Source<WebContents>(web_contents_)); - MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +bool ExecuteJavaScriptAndExtractInt(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script, + int* result) { + DCHECK(result); + scoped_ptr<Value> value(ExecuteJavaScript(tab_contents, frame_xpath, script)); + if (!value.get()) + return false; + + return value->GetAsInteger(result); } -std::string JavaScriptRunner::Run() { - // The DOMAutomationController requires an automation ID, even though we are - // not using it in this case. - web_contents_->render_view_host()->ExecuteJavascriptInWebFrame( - frame_xpath_, L"window.domAutomationController.setAutomationId(0);"); +bool ExecuteJavaScriptAndExtractBool(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script, + bool* result) { + DCHECK(result); + scoped_ptr<Value> value(ExecuteJavaScript(tab_contents, frame_xpath, script)); + if (!value.get()) + return false; - web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(frame_xpath_, - jscript_); - ui_test_utils::RunMessageLoop(); - return result_; + return value->GetAsBoolean(result); } +bool ExecuteJavaScriptAndExtractString(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script, + std::string* result) { + DCHECK(result); + scoped_ptr<Value> value(ExecuteJavaScript(tab_contents, frame_xpath, script)); + if (!value.get()) + return false; + + return value->GetAsString(result); +} } // namespace ui_test_utils diff --git a/chrome/test/ui_test_utils.h b/chrome/test/ui_test_utils.h index 863c758..3c166e8 100644 --- a/chrome/test/ui_test_utils.h +++ b/chrome/test/ui_test_utils.h @@ -13,7 +13,8 @@ class Browser; class GURL; class NavigationController; -class WebContents; +class Value; +class TabContents; // A collections of functions designed for use with InProcessBrowserTest. namespace ui_test_utils { @@ -43,38 +44,32 @@ void NavigateToURLBlockUntilNavigationsComplete(Browser* browser, int number_of_navigations); -// This class enables you to send JavaScript as a string from the browser to the -// renderer for execution in a frame of your choice. -class JavaScriptRunner : public NotificationObserver { - public: - // Constructor. |web_contents| is a pointer to the WebContents you want to run - // the JavaScript code in. |frame_xpath| is a path to the frame to run it in. - // |jscript| is a string containing the JavaScript code to run, for example: - // "window.domAutomationController.send(alert('hello world'));". The - // JavaScript code will execute when Run is called. Note: In order for the - // domAutomationController to work, you must call EnableDOMAutomation() in - // your test class first. - JavaScriptRunner(WebContents* web_contents, - const std::wstring& frame_xpath, - const std::wstring& jscript); - - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - // Executes the JavaScript code passed in to the constructor. See also comment - // about EnableDOMAutomation in the constructor. - std::string Run(); - - private: - WebContents* web_contents_; - std::wstring frame_xpath_; - std::wstring jscript_; - std::string result_; - - DISALLOW_COPY_AND_ASSIGN(JavaScriptRunner); -}; - +// Executes the passed |script| in the frame pointed to by |frame_xpath| (use +// empty string for main frame) and returns the value the evaluation of the +// script returned. The caller owns the returned value. +Value* ExecuteJavaScript(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script); + +// The following methods executes the passed |script| in the frame pointed to by +// |frame_xpath| (use empty string for main frame) and sets |result| to the +// value returned by the script evaluation. +// They return true on success, false if the script evaluation failed or did not +// evaluate to the expected type. +// Note: In order for the domAutomationController to work, you must call +// EnableDOMAutomation() in your test first. +bool ExecuteJavaScriptAndExtractInt(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script, + int* result); +bool ExecuteJavaScriptAndExtractBool(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script, + bool* result); +bool ExecuteJavaScriptAndExtractString(TabContents* tab_contents, + const std::wstring& frame_xpath, + const std::wstring& script, + std::string* result); } #endif // CHROME_TEST_UI_TEST_UTILS_H_ |