Home | History | Annotate | Download | only in apps
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/strings/stringprintf.h"
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "base/win/windows_version.h"
      8 #include "chrome/browser/apps/app_browsertest_util.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/extensions/extension_test_message_listener.h"
     11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     12 #include "chrome/common/chrome_switches.h"
     13 #include "chrome/test/base/ui_test_utils.h"
     14 #include "content/public/common/page_transition_types.h"
     15 #include "content/public/test/browser_test_base.h"
     16 #include "content/public/test/browser_test_utils.h"
     17 #include "net/test/embedded_test_server/embedded_test_server.h"
     18 
     19 namespace extensions {
     20 
     21 class PlatformAppUrlRedirectorBrowserTest : public PlatformAppBrowserTest {
     22  public:
     23   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
     24 
     25  protected:
     26   // Performs the following sequence:
     27   // - installs the app |handler| (a relative path under the platform_apps
     28   // subdirectory);
     29   // - navigates the current tab to the HTML page |lancher_page| (ditto);
     30   // - then waits for |handler| to launch and send back a |handler_ack_message|;
     31   // - finally checks that the resulting app window count is as expected.
     32   // The |launcher_page| is supposed to trigger a navigation matching one of the
     33   // url_handlers in the |handler|'s manifest, and thereby launch the |handler|.
     34   void TestNavigationInTab(const char* launcher_page,
     35                            const char* handler,
     36                            const char* handler_start_message);
     37 
     38   // The same as above, but does not expect the |handler| to launch. Verifies
     39   // that it didn't, and that the navigation has opened in a new tab instead.
     40   void TestMismatchingNavigationInTab(const char* launcher_page,
     41                                       const char* success_tab_title,
     42                                       const char* handler);
     43 
     44   // - installs the app |handler|;
     45   // - opens the page |xhr_opening_page| in the current tab;
     46   // - the page sends an XHR to a local resouce, whose URL matches one of the
     47   //   url_handlers in |handler|;
     48   // - waits until |xhr_opening_page| gets a response back and changes the tab's
     49   //   title to a value indicating success/failure of the XHR;
     50   // - verifies that no app windows have been opened, i.e. |handler| wasn't
     51   //   launched even though its url_handlers match the URL.
     52   void TestNegativeXhrInTab(const char* xhr_opening_page,
     53                             const char* success_tab_title,
     54                             const char* failure_tab_title,
     55                             const char* handler);
     56 
     57   // Performs the following sequence:
     58   // - installs the app |handler| (a relative path under the platform_apps
     59   // subdirectory);
     60   // - loads and launches the app |launcher| (ditto);
     61   // - waits for the |launcher| to launch and send back a |launcher_ack_message|
     62   //   (to make sure it's not the failing entity, if the test fails overall);
     63   // - waits for the |handler| to launch and send back a |handler_ack_message|;
     64   // - finally checks that the resulting app window count is as expected.
     65   // The |launcher| is supposed to trigger a navigation matching one of the
     66   // url_handlers in the |handler|'s manifest, and thereby launch the |handler|.
     67   void TestNavigationInApp(const char* launcher,
     68                            const char* launcher_done_message,
     69                            const char* handler,
     70                            const char* handler_start_message);
     71 
     72   // The same as above, but does not expect the |handler| to launch. Verifies
     73   // that it didn't, and that the navigation has opened in a new tab instead.
     74   void TestMismatchingNavigationInApp(const char* launcher,
     75                                       const char* launcher_done_message,
     76                                       const char* handler);
     77 
     78   // - installs the |handler| app;
     79   // - loads and launches the |launcher| app;
     80   // - waits until the |launcher| sends back a |launcher_done_message|;
     81   // - the launcher performs a navigation to a URL that mismatches the
     82   //   |handler|'s url_handlers;
     83   // - verifies that the |handler| hasn't been launched as a result of the
     84   //   navigation.
     85   void TestNegativeNavigationInApp(const char* launcher,
     86                                    const char* launcher_done_message,
     87                                    const char* handler);
     88 
     89   // - installs the app |handler|;
     90   // - navigates the current tab to the HTML page |matching_target_page| with
     91   //   page transition |transition|;
     92   // - waits for |handler| to launch and send back a |handler_start_message|;
     93   // - finally checks that the resulting app window count is as expected.
     94   void TestNavigationInBrowser(const char* matching_target_page,
     95                                content::PageTransition transition,
     96                                const char* handler,
     97                                const char* handler_start_message);
     98 
     99   // Same as above, but does not expect |handler| to launch. This is used, e.g.
    100   // for form submissions, where the URL would normally match the url_handlers
    101   // but should not launch it.
    102   void TestNegativeNavigationInBrowser(const char* matching_target_page,
    103                                        content::PageTransition transition,
    104                                        const char* success_tab_title,
    105                                        const char* handler);
    106 
    107   // Same as above, but expects the |mismatching_target_page| should not match
    108   // any of the |handler|'s url_handlers, and therefor not launch the app.
    109   void TestMismatchingNavigationInBrowser(const char* mismatching_target_page,
    110                                           content::PageTransition transition,
    111                                           const char* success_tab_title,
    112                                           const char* handler);
    113 };
    114 
    115 
    116 void PlatformAppUrlRedirectorBrowserTest::SetUpCommandLine(
    117     CommandLine* command_line) {
    118   PlatformAppBrowserTest::SetUpCommandLine(command_line);
    119   command_line->AppendSwitch(::switches::kDisablePopupBlocking);
    120   command_line->AppendSwitchASCII(::switches::kPrerenderMode,
    121                                   ::switches::kPrerenderModeSwitchValueEnabled);
    122 }
    123 
    124 // TODO(sergeygs): Factor out common functionality from TestXyz,
    125 // TestNegativeXyz, and TestMismatchingXyz versions.
    126 
    127 // TODO(sergeys): Return testing::AssertionErrors from these methods to
    128 // preserve line numbers and (if applicable) failure messages.
    129 
    130 void PlatformAppUrlRedirectorBrowserTest::TestNavigationInTab(
    131     const char* launcher_page,
    132     const char* handler,
    133     const char* handler_start_message) {
    134   ASSERT_TRUE(StartEmbeddedTestServer());
    135 
    136   InstallPlatformApp(handler);
    137 
    138   ExtensionTestMessageListener handler_listener(handler_start_message, false);
    139 
    140   ui_test_utils::NavigateToURLWithDisposition(
    141       browser(),
    142       embedded_test_server()->GetURL(base::StringPrintf(
    143           "/extensions/platform_apps/%s", launcher_page)),
    144       CURRENT_TAB,
    145       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    146 
    147   ASSERT_TRUE(handler_listener.WaitUntilSatisfied());
    148 
    149   ASSERT_EQ(1U, GetAppWindowCount());
    150 }
    151 
    152 void PlatformAppUrlRedirectorBrowserTest::TestMismatchingNavigationInTab(
    153     const char* launcher_page,
    154     const char* success_tab_title,
    155     const char* handler) {
    156   ASSERT_TRUE(StartEmbeddedTestServer());
    157 
    158   InstallPlatformApp(handler);
    159 
    160   const base::string16 success_title = base::ASCIIToUTF16(success_tab_title);
    161   content::WebContents* tab =
    162       browser()->tab_strip_model()->GetActiveWebContents();
    163   content::TitleWatcher title_watcher(tab, success_title);
    164 
    165   ui_test_utils::NavigateToURLWithDisposition(
    166       browser(),
    167       embedded_test_server()->GetURL(base::StringPrintf(
    168           "/extensions/platform_apps/%s", launcher_page)),
    169       CURRENT_TAB,
    170       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    171 
    172   ASSERT_EQ(success_title, title_watcher.WaitAndGetTitle());
    173   ASSERT_EQ(1, browser()->tab_strip_model()->count());
    174   ASSERT_EQ(0U, GetAppWindowCount());
    175 }
    176 
    177 void PlatformAppUrlRedirectorBrowserTest::TestNegativeXhrInTab(
    178     const char* launcher_page,
    179     const char* success_tab_title,
    180     const char* failure_tab_title,
    181     const char* handler) {
    182   ASSERT_TRUE(StartEmbeddedTestServer());
    183 
    184   InstallPlatformApp(handler);
    185 
    186   const base::string16 success_title = base::ASCIIToUTF16(success_tab_title);
    187   const base::string16 failure_title = base::ASCIIToUTF16(failure_tab_title);
    188   content::WebContents* tab =
    189       browser()->tab_strip_model()->GetActiveWebContents();
    190   content::TitleWatcher title_watcher(tab, success_title);
    191   title_watcher.AlsoWaitForTitle(failure_title);
    192 
    193   ui_test_utils::NavigateToURLWithDisposition(
    194       browser(),
    195       embedded_test_server()->GetURL(base::StringPrintf(
    196           "/extensions/platform_apps/%s", launcher_page)),
    197       CURRENT_TAB,
    198       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    199 
    200   ASSERT_EQ(success_title, title_watcher.WaitAndGetTitle());
    201   ASSERT_EQ(1, browser()->tab_strip_model()->count());
    202   ASSERT_EQ(0U, GetAppWindowCount());
    203 }
    204 
    205 void PlatformAppUrlRedirectorBrowserTest::TestNavigationInApp(
    206     const char* launcher,
    207     const char* launcher_done_message,
    208     const char* handler,
    209     const char* handler_start_message) {
    210   ASSERT_TRUE(StartEmbeddedTestServer());
    211 
    212   InstallPlatformApp(handler);
    213 
    214   ExtensionTestMessageListener handler_listener(handler_start_message, false);
    215 
    216   LoadAndLaunchPlatformApp(launcher, launcher_done_message);
    217 
    218   ASSERT_TRUE(handler_listener.WaitUntilSatisfied());
    219 
    220   ASSERT_EQ(2U, GetAppWindowCount());
    221 }
    222 
    223 void PlatformAppUrlRedirectorBrowserTest::TestNegativeNavigationInApp(
    224     const char* launcher,
    225     const char* launcher_done_message,
    226     const char* handler) {
    227   ASSERT_TRUE(StartEmbeddedTestServer());
    228 
    229   InstallPlatformApp(handler);
    230 
    231   content::WindowedNotificationObserver observer(
    232       chrome::NOTIFICATION_TAB_ADDED,
    233       content::Source<content::WebContentsDelegate>(browser()));
    234 
    235   LoadAndLaunchPlatformApp(launcher, launcher_done_message);
    236 
    237   observer.Wait();
    238 
    239   ASSERT_EQ(1U, GetAppWindowCount());
    240 }
    241 
    242 void PlatformAppUrlRedirectorBrowserTest::TestMismatchingNavigationInApp(
    243     const char* launcher,
    244     const char* launcher_done_message,
    245     const char* handler) {
    246   ASSERT_TRUE(StartEmbeddedTestServer());
    247 
    248   InstallPlatformApp(handler);
    249 
    250   content::WindowedNotificationObserver observer(
    251       chrome::NOTIFICATION_TAB_ADDED,
    252       content::Source<content::WebContentsDelegate>(browser()));
    253 
    254   LoadAndLaunchPlatformApp(launcher, launcher_done_message);
    255 
    256   observer.Wait();
    257   ASSERT_EQ(1U, GetAppWindowCount());
    258   ASSERT_EQ(2, browser()->tab_strip_model()->count());
    259 }
    260 
    261 void PlatformAppUrlRedirectorBrowserTest::TestNavigationInBrowser(
    262     const char* matching_target_page,
    263     content::PageTransition transition,
    264     const char* handler,
    265     const char* handler_start_message) {
    266   ASSERT_TRUE(StartEmbeddedTestServer());
    267 
    268   InstallPlatformApp(handler);
    269 
    270   ExtensionTestMessageListener handler_listener(handler_start_message, false);
    271 
    272   chrome::NavigateParams params(
    273       browser(),
    274       embedded_test_server()->GetURL(base::StringPrintf(
    275            "/extensions/platform_apps/%s", matching_target_page)),
    276       transition);
    277   ui_test_utils::NavigateToURL(&params);
    278 
    279   ASSERT_TRUE(handler_listener.WaitUntilSatisfied());
    280 
    281   ASSERT_EQ(1U, GetAppWindowCount());
    282 }
    283 
    284 void PlatformAppUrlRedirectorBrowserTest::TestNegativeNavigationInBrowser(
    285     const char* matching_target_page,
    286     content::PageTransition transition,
    287     const char* success_tab_title,
    288     const char* handler) {
    289   ASSERT_TRUE(StartEmbeddedTestServer());
    290 
    291   InstallPlatformApp(handler);
    292 
    293   const base::string16 success_title = base::ASCIIToUTF16(success_tab_title);
    294   content::WebContents* tab =
    295       browser()->tab_strip_model()->GetActiveWebContents();
    296   content::TitleWatcher title_watcher(tab, success_title);
    297 
    298   chrome::NavigateParams params(
    299       browser(),
    300       embedded_test_server()->GetURL(base::StringPrintf(
    301            "/extensions/platform_apps/%s", matching_target_page)),
    302       transition);
    303   ui_test_utils::NavigateToURL(&params);
    304 
    305   ASSERT_EQ(success_title, title_watcher.WaitAndGetTitle());
    306   ASSERT_EQ(0U, GetAppWindowCount());
    307 }
    308 
    309 void PlatformAppUrlRedirectorBrowserTest::TestMismatchingNavigationInBrowser(
    310     const char* mismatching_target_page,
    311     content::PageTransition transition,
    312     const char* success_tab_title,
    313     const char* handler) {
    314   TestNegativeNavigationInBrowser(
    315       mismatching_target_page, transition, success_tab_title, handler);
    316 }
    317 
    318 // Test that a click on a regular link in a tab launches an app that has
    319 // matching url_handlers.
    320 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    321                        ClickInTabIntercepted) {
    322 #if defined (OS_WIN)
    323   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    324 #endif
    325   TestNavigationInTab(
    326       "url_handlers/launching_pages/click_link.html",
    327       "url_handlers/handlers/simple",
    328       "Handler launched");
    329 }
    330 
    331 // Test that a click on a target='_blank' link in a tab launches an app that has
    332 // matching url_handlers.
    333 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    334                        BlankClickInTabIntercepted) {
    335 #if defined (OS_WIN)
    336   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    337 #endif
    338   TestNavigationInTab(
    339       "url_handlers/launching_pages/click_blank_link.html",
    340       "url_handlers/handlers/simple",
    341       "Handler launched");
    342 }
    343 
    344 // Test that a call to window.open() in a tab launches an app that has
    345 // matching url_handlers.
    346 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    347                        WindowOpenInTabIntercepted) {
    348 #if defined (OS_WIN)
    349   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    350 #endif
    351   TestNavigationInTab(
    352       "url_handlers/launching_pages/call_window_open.html",
    353       "url_handlers/handlers/simple",
    354       "Handler launched");
    355 }
    356 
    357 // Test that a click on a regular link in a tab launches an app that has
    358 // matching url_handlers.
    359 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    360                        MismatchingClickInTabNotIntercepted) {
    361 #if defined (OS_WIN)
    362   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    363 #endif
    364   TestMismatchingNavigationInTab(
    365       "url_handlers/launching_pages/click_mismatching_link.html",
    366       "Mismatching link target loaded",
    367       "url_handlers/handlers/simple");
    368 }
    369 
    370 // Test that a click on target='_blank' link in an app's window launches
    371 // another app that has matching url_handlers.
    372 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    373                        BlankClickInAppIntercepted) {
    374 #if defined (OS_WIN)
    375   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    376 #endif
    377   TestNavigationInApp(
    378       "url_handlers/launchers/click_blank_link",
    379       "Launcher done",
    380       "url_handlers/handlers/simple",
    381       "Handler launched");
    382 }
    383 
    384 // Test that a call to window.open() in the app's foreground page launches
    385 // another app that has matching url_handlers.
    386 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    387                        WindowOpenInAppIntercepted) {
    388 #if defined (OS_WIN)
    389   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    390 #endif
    391   TestNavigationInApp(
    392       "url_handlers/launchers/call_window_open",
    393       "Launcher done",
    394       "url_handlers/handlers/simple",
    395       "Handler launched");
    396 }
    397 
    398 // Test that an app with url_handlers does not intercept a mismatching
    399 // click on a target='_blank' link in another app's window.
    400 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    401                        MismatchingWindowOpenInAppNotIntercepted) {
    402 #if defined (OS_WIN)
    403   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    404 #endif
    405   TestMismatchingNavigationInApp(
    406       "url_handlers/launchers/call_mismatching_window_open",
    407       "Launcher done",
    408       "url_handlers/handlers/simple");
    409 }
    410 
    411 // Test that a webview in an app can be navigated to a URL without interception
    412 // even when there are other (or the same) apps that have matching url_handlers.
    413 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    414                        WebviewNavigationNotIntercepted) {
    415 #if defined (OS_WIN)
    416   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    417 #endif
    418   // The launcher clicks on a link, which gets intercepted and launches the
    419   // handler. The handler also redirects an embedded webview to the URL. The
    420   // webview should just navigate without creating an endless loop of
    421   // navigate-intercept-launch sequences with multiplying handler's windows.
    422   // There should be 2 windows only: launcher's and handler's.
    423   TestNavigationInApp(
    424       "url_handlers/launchers/click_blank_link",
    425       "Launcher done",
    426       "url_handlers/handlers/navigate_webview_to_url",
    427       "Handler launched");
    428 }
    429 
    430 // Test that a webview in an app can be navigated to a URL without interception
    431 // even when there are other (or the same) apps that have matching url_handlers.
    432 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    433                        MismatchingBlankClickInAppNotIntercepted) {
    434 #if defined (OS_WIN)
    435   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    436 #endif
    437   // The launcher clicks on a link, which gets intercepted and launches the
    438   // handler. The handler also redirects an embedded webview to the URL. The
    439   // webview should just navigate without creating an endless loop of
    440   // navigate-intercept-launch sequences with multiplying handler's windows.
    441   // There should be 2 windows only: launcher's and handler's.
    442   TestMismatchingNavigationInApp(
    443       "url_handlers/launchers/click_mismatching_blank_link",
    444       "Launcher done",
    445       "url_handlers/handlers/simple");
    446 }
    447 
    448 // Test that a URL entry in the omnibar launches an app that has matching
    449 // url_handlers.
    450 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    451                        EntryInOmnibarIntercepted) {
    452 #if defined (OS_WIN)
    453   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    454 #endif
    455   TestNavigationInBrowser(
    456       "url_handlers/common/target.html",
    457       content::PAGE_TRANSITION_TYPED,
    458       "url_handlers/handlers/simple",
    459       "Handler launched");
    460 }
    461 
    462 // Test that an app with url_handlers does not intercept a mismatching
    463 // URL entry in the omnibar.
    464 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    465                        MismatchingEntryInOmnibarNotIntercepted) {
    466 #if defined (OS_WIN)
    467   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    468 #endif
    469   TestMismatchingNavigationInBrowser(
    470       "url_handlers/common/mismatching_target.html",
    471       content::PAGE_TRANSITION_TYPED,
    472       "Mismatching link target loaded",
    473       "url_handlers/handlers/simple");
    474 }
    475 
    476 // Test that a form submission in a page is never subject to interception
    477 // by apps even with matching url_handlers.
    478 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    479                        FormSubmissionInTabNotIntercepted) {
    480 #if defined (OS_WIN)
    481   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    482 #endif
    483   TestMismatchingNavigationInTab(
    484       "url_handlers/launching_pages/submit_form.html",
    485       "Link target loaded",
    486       "url_handlers/handlers/simple");
    487 }
    488 
    489 // Test that a form submission in a page is never subject to interception
    490 // by apps even with matching url_handlers.
    491 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    492                        XhrInTabNotIntercepted) {
    493 #if defined (OS_WIN)
    494   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    495 #endif
    496   TestNegativeXhrInTab(
    497       "url_handlers/xhr_downloader/main.html",
    498       "XHR succeeded",
    499       "XHR failed",
    500       "url_handlers/handlers/steal_xhr_target");
    501 }
    502 
    503 // Test that a click on a prerendered link still launches.
    504 IN_PROC_BROWSER_TEST_F(PlatformAppUrlRedirectorBrowserTest,
    505                        PrerenderedClickInTabIntercepted) {
    506 #if defined (OS_WIN)
    507   if (base::win::GetVersion() < base::win::VERSION_VISTA) return;  // Bug 301638
    508 #endif
    509   TestNavigationInTab(
    510       "url_handlers/launching_pages/prerender_link.html",
    511       "url_handlers/handlers/simple",
    512       "Handler launched");
    513 }
    514 
    515 }  // namespace extensions
    516