Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 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 "chrome/browser/extensions/extension_apitest.h"
      8 #include "chrome/browser/extensions/extension_service.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "chrome/browser/ui/browser.h"
     11 #include "chrome/browser/ui/browser_commands.h"
     12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     13 #include "chrome/common/url_constants.h"
     14 #include "chrome/test/base/ui_test_utils.h"
     15 #include "content/public/browser/render_process_host.h"
     16 #include "content/public/browser/render_view_host.h"
     17 #include "content/public/browser/site_instance.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/test/browser_test_utils.h"
     20 #include "extensions/browser/extension_host.h"
     21 #include "extensions/browser/process_map.h"
     22 #include "extensions/common/switches.h"
     23 #include "net/dns/mock_host_resolver.h"
     24 #include "net/test/embedded_test_server/embedded_test_server.h"
     25 #include "net/test/embedded_test_server/http_request.h"
     26 #include "net/test/embedded_test_server/http_response.h"
     27 
     28 using content::ExecuteScript;
     29 using content::ExecuteScriptAndExtractString;
     30 using content::NavigationController;
     31 using content::WebContents;
     32 using content::RenderViewHost;
     33 
     34 namespace {
     35 
     36 std::string WrapForJavascriptAndExtract(const char* javascript_expression) {
     37   return std::string("window.domAutomationController.send(") +
     38       javascript_expression + ")";
     39 }
     40 
     41 scoped_ptr<net::test_server::HttpResponse> HandleExpectAndSetCookieRequest(
     42     const net::test_server::EmbeddedTestServer* test_server,
     43     const net::test_server::HttpRequest& request) {
     44   if (!StartsWithASCII(request.relative_url, "/expect-and-set-cookie?", true))
     45     return scoped_ptr<net::test_server::HttpResponse>();
     46 
     47   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
     48       new net::test_server::BasicHttpResponse);
     49   http_response->set_code(net::HTTP_OK);
     50 
     51   std::string request_cookies;
     52   std::map<std::string, std::string>::const_iterator it =
     53       request.headers.find("Cookie");
     54   if (it != request.headers.end())
     55     request_cookies = it->second;
     56 
     57   size_t query_string_pos = request.relative_url.find('?');
     58   std::string query_string =
     59       request.relative_url.substr(query_string_pos + 1);
     60   url::Component query(0, query_string.length()), key_pos, value_pos;
     61   bool expectations_satisfied = true;
     62   std::vector<std::string> cookies_to_set;
     63   while (url::ExtractQueryKeyValue(query_string.c_str(), &query, &key_pos,
     64                                    &value_pos)) {
     65     std::string escaped_key(query_string.substr(key_pos.begin, key_pos.len));
     66     std::string escaped_value(
     67         query_string.substr(value_pos.begin, value_pos.len));
     68 
     69     std::string key =
     70         net::UnescapeURLComponent(escaped_key,
     71                                   net::UnescapeRule::NORMAL |
     72                                   net::UnescapeRule::SPACES |
     73                                   net::UnescapeRule::URL_SPECIAL_CHARS);
     74 
     75     std::string value =
     76         net::UnescapeURLComponent(escaped_value,
     77                                   net::UnescapeRule::NORMAL |
     78                                   net::UnescapeRule::SPACES |
     79                                   net::UnescapeRule::URL_SPECIAL_CHARS);
     80 
     81     if (key == "expect") {
     82       if (request_cookies.find(value) == std::string::npos)
     83         expectations_satisfied = false;
     84     } else if (key == "set") {
     85       cookies_to_set.push_back(value);
     86     } else {
     87       return scoped_ptr<net::test_server::HttpResponse>();
     88     }
     89   }
     90 
     91   if (expectations_satisfied) {
     92     for (size_t i = 0; i < cookies_to_set.size(); i++)
     93       http_response->AddCustomHeader("Set-Cookie", cookies_to_set[i]);
     94   }
     95 
     96   return http_response.PassAs<net::test_server::HttpResponse>();
     97 }
     98 
     99 class IsolatedAppTest : public ExtensionBrowserTest {
    100  public:
    101   // Returns whether the given tab's current URL has the given cookie.
    102   bool WARN_UNUSED_RESULT HasCookie(WebContents* contents, std::string cookie) {
    103     int value_size;
    104     std::string actual_cookie;
    105     ui_test_utils::GetCookies(contents->GetURL(), contents, &value_size,
    106                               &actual_cookie);
    107     return actual_cookie.find(cookie) != std::string::npos;
    108   }
    109 
    110   const extensions::Extension* GetInstalledApp(WebContents* contents) {
    111     const extensions::Extension* installed_app = NULL;
    112     Profile* profile =
    113         Profile::FromBrowserContext(contents->GetBrowserContext());
    114     ExtensionService* service = profile->GetExtensionService();
    115     if (service) {
    116       std::set<std::string> extension_ids =
    117           extensions::ProcessMap::Get(profile)->GetExtensionsInProcess(
    118               contents->GetRenderViewHost()->GetProcess()->GetID());
    119       for (std::set<std::string>::iterator iter = extension_ids.begin();
    120            iter != extension_ids.end(); ++iter) {
    121         installed_app = service->extensions()->GetByID(*iter);
    122         if (installed_app && installed_app->is_app())
    123           return installed_app;
    124       }
    125     }
    126     return NULL;
    127   }
    128 
    129  private:
    130   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    131     ExtensionBrowserTest::SetUpCommandLine(command_line);
    132     command_line->AppendSwitch(
    133         extensions::switches::kEnableExperimentalExtensionApis);
    134   }
    135 };
    136 
    137 }  // namespace
    138 
    139 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, CrossProcessClientRedirect) {
    140   host_resolver()->AddRule("*", "127.0.0.1");
    141   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    142 
    143   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
    144   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
    145 
    146   GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
    147   GURL::Replacements replace_host;
    148   std::string host_str("localhost");  // Must stay in scope with replace_host.
    149   replace_host.SetHostStr(host_str);
    150   base_url = base_url.ReplaceComponents(replace_host);
    151   ui_test_utils::NavigateToURLWithDisposition(
    152       browser(), base_url.Resolve("app1/main.html"),
    153       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    154 
    155   // Redirect to app2.
    156   GURL redirect_url(embedded_test_server()->GetURL(
    157       "/extensions/isolated_apps/app2/redirect.html"));
    158   ui_test_utils::NavigateToURLWithDisposition(
    159       browser(), redirect_url,
    160       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    161 
    162   // Go back twice.
    163   // If bug fixed, we cannot go back anymore.
    164   // If not fixed, we will redirect back to app2 and can go back again.
    165   EXPECT_TRUE(chrome::CanGoBack(browser()));
    166   chrome::GoBack(browser(), CURRENT_TAB);
    167   EXPECT_TRUE(chrome::CanGoBack(browser()));
    168   chrome::GoBack(browser(), CURRENT_TAB);
    169   EXPECT_FALSE(chrome::CanGoBack(browser()));
    170 
    171   // We also need to test script-initialized navigation (document.location.href)
    172   // happened after page finishes loading. This one will also triggered the
    173   // willPerformClientRedirect hook in RenderViewImpl but should not replace
    174   // the previous history entry.
    175   ui_test_utils::NavigateToURLWithDisposition(
    176       browser(), base_url.Resolve("non_app/main.html"),
    177       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    178 
    179   WebContents* tab0 = browser()->tab_strip_model()->GetWebContentsAt(1);
    180 
    181   // Using JavaScript to navigate to app2 page,
    182   // after the non_app page has finished loading.
    183   content::WindowedNotificationObserver observer1(
    184       content::NOTIFICATION_LOAD_STOP,
    185       content::Source<NavigationController>(
    186           &browser()->tab_strip_model()->GetActiveWebContents()->
    187               GetController()));
    188   std::string script = base::StringPrintf(
    189         "document.location.href=\"%s\";",
    190         base_url.Resolve("app2/main.html").spec().c_str());
    191   EXPECT_TRUE(ExecuteScript(tab0, script));
    192   observer1.Wait();
    193 
    194   // This kind of navigation should not replace previous navigation entry.
    195   EXPECT_TRUE(chrome::CanGoBack(browser()));
    196   chrome::GoBack(browser(), CURRENT_TAB);
    197   EXPECT_FALSE(chrome::CanGoBack(browser()));
    198 }
    199 
    200 // Tests that cookies set within an isolated app are not visible to normal
    201 // pages or other apps.
    202 //
    203 // TODO(ajwong): Also test what happens if an app spans multiple sites in its
    204 // extent.  These origins should also be isolated, but still have origin-based
    205 // separation as you would expect.
    206 //
    207 // This test is disabled due to being flaky. http://crbug.com/86562
    208 #if defined(OS_WIN)
    209 #define MAYBE_CookieIsolation DISABLED_CookieIsolation
    210 #else
    211 #define MAYBE_CookieIsolation CookieIsolation
    212 #endif
    213 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_CookieIsolation) {
    214   host_resolver()->AddRule("*", "127.0.0.1");
    215   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    216 
    217   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
    218   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
    219 
    220   // The app under test acts on URLs whose host is "localhost",
    221   // so the URLs we navigate to must have host "localhost".
    222   GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
    223   GURL::Replacements replace_host;
    224   std::string host_str("localhost");  // Must stay in scope with replace_host.
    225   replace_host.SetHostStr(host_str);
    226   base_url = base_url.ReplaceComponents(replace_host);
    227 
    228   ui_test_utils::NavigateToURLWithDisposition(
    229       browser(), base_url.Resolve("app1/main.html"),
    230       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    231   ui_test_utils::NavigateToURLWithDisposition(
    232       browser(), base_url.Resolve("app2/main.html"),
    233       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    234   ui_test_utils::NavigateToURLWithDisposition(
    235       browser(), base_url.Resolve("non_app/main.html"),
    236       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    237 
    238   ASSERT_EQ(3, browser()->tab_strip_model()->count());
    239 
    240   // Ensure first two tabs have installed apps.
    241   WebContents* tab0 = browser()->tab_strip_model()->GetWebContentsAt(0);
    242   WebContents* tab1 = browser()->tab_strip_model()->GetWebContentsAt(1);
    243   WebContents* tab2 = browser()->tab_strip_model()->GetWebContentsAt(2);
    244   ASSERT_TRUE(GetInstalledApp(tab0));
    245   ASSERT_TRUE(GetInstalledApp(tab1));
    246   ASSERT_TRUE(!GetInstalledApp(tab2));
    247 
    248   // Check that tabs see cannot each other's localStorage even though they are
    249   // in the same origin.
    250   ASSERT_TRUE(ExecuteScript(
    251       tab0, "window.localStorage.setItem('testdata', 'ls_app1');"));
    252   ASSERT_TRUE(ExecuteScript(
    253       tab1, "window.localStorage.setItem('testdata', 'ls_app2');"));
    254   ASSERT_TRUE(ExecuteScript(
    255       tab2, "window.localStorage.setItem('testdata', 'ls_normal');"));
    256 
    257   const std::string& kRetrieveLocalStorage =
    258       WrapForJavascriptAndExtract(
    259           "window.localStorage.getItem('testdata') || 'badval'");
    260   std::string result;
    261   ASSERT_TRUE(ExecuteScriptAndExtractString(
    262       tab0, kRetrieveLocalStorage.c_str(), &result));
    263   EXPECT_EQ("ls_app1", result);
    264   ASSERT_TRUE(ExecuteScriptAndExtractString(
    265       tab1, kRetrieveLocalStorage.c_str(), &result));
    266   EXPECT_EQ("ls_app2", result);
    267   ASSERT_TRUE(ExecuteScriptAndExtractString(
    268       tab2, kRetrieveLocalStorage.c_str(), &result));
    269   EXPECT_EQ("ls_normal", result);
    270 
    271   // Check that each tab sees its own cookie.
    272   EXPECT_TRUE(HasCookie(tab0, "app1=3"));
    273   EXPECT_TRUE(HasCookie(tab1, "app2=4"));
    274   EXPECT_TRUE(HasCookie(tab2, "normalPage=5"));
    275 
    276   // Check that app1 tab cannot see the other cookies.
    277   EXPECT_FALSE(HasCookie(tab0, "app2"));
    278   EXPECT_FALSE(HasCookie(tab0, "normalPage"));
    279 
    280   // Check that app2 tab cannot see the other cookies.
    281   EXPECT_FALSE(HasCookie(tab1, "app1"));
    282   EXPECT_FALSE(HasCookie(tab1, "normalPage"));
    283 
    284   // Check that normal tab cannot see the other cookies.
    285   EXPECT_FALSE(HasCookie(tab2, "app1"));
    286   EXPECT_FALSE(HasCookie(tab2, "app2"));
    287 
    288   // Check that the non_app iframe cookie is associated with app1 and not the
    289   // normal tab.  (For now, iframes are always rendered in their parent
    290   // process, even if they aren't in the app manifest.)
    291   EXPECT_TRUE(HasCookie(tab0, "nonAppFrame=6"));
    292   EXPECT_FALSE(HasCookie(tab2, "nonAppFrame"));
    293 
    294   // Check that isolation persists even if the tab crashes and is reloaded.
    295   chrome::SelectNumberedTab(browser(), 0);
    296   content::CrashTab(tab0);
    297   content::WindowedNotificationObserver observer(
    298       content::NOTIFICATION_LOAD_STOP,
    299       content::Source<NavigationController>(
    300           &browser()->tab_strip_model()->GetActiveWebContents()->
    301               GetController()));
    302   chrome::Reload(browser(), CURRENT_TAB);
    303   observer.Wait();
    304   EXPECT_TRUE(HasCookie(tab0, "app1=3"));
    305   EXPECT_FALSE(HasCookie(tab0, "app2"));
    306   EXPECT_FALSE(HasCookie(tab0, "normalPage"));
    307 
    308 }
    309 
    310 // This test is disabled due to being flaky. http://crbug.com/145588
    311 // Ensure that cookies are not isolated if the isolated apps are not installed.
    312 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_NoCookieIsolationWithoutApp) {
    313   host_resolver()->AddRule("*", "127.0.0.1");
    314   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    315 
    316   // The app under test acts on URLs whose host is "localhost",
    317   // so the URLs we navigate to must have host "localhost".
    318   GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
    319   GURL::Replacements replace_host;
    320   std::string host_str("localhost");  // Must stay in scope with replace_host.
    321   replace_host.SetHostStr(host_str);
    322   base_url = base_url.ReplaceComponents(replace_host);
    323 
    324   ui_test_utils::NavigateToURLWithDisposition(
    325       browser(), base_url.Resolve("app1/main.html"),
    326       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    327   ui_test_utils::NavigateToURLWithDisposition(
    328       browser(), base_url.Resolve("app2/main.html"),
    329       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    330   ui_test_utils::NavigateToURLWithDisposition(
    331       browser(), base_url.Resolve("non_app/main.html"),
    332       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    333 
    334   ASSERT_EQ(3, browser()->tab_strip_model()->count());
    335 
    336   // Check that tabs see each other's cookies.
    337   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
    338                         "app2=4"));
    339   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
    340                         "normalPage=5"));
    341   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
    342                         "nonAppFrame=6"));
    343   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
    344                         "app1=3"));
    345   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
    346                         "normalPage=5"));
    347   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
    348                         "nonAppFrame=6"));
    349   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
    350                         "app1=3"));
    351   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
    352                         "app2=4"));
    353   EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
    354                         "nonAppFrame=6"));
    355 
    356   // Check that all tabs share the same localStorage if they have the same
    357   // origin.
    358   WebContents* app1_wc = browser()->tab_strip_model()->GetWebContentsAt(0);
    359   WebContents* app2_wc = browser()->tab_strip_model()->GetWebContentsAt(1);
    360   WebContents* non_app_wc = browser()->tab_strip_model()->GetWebContentsAt(2);
    361   ASSERT_TRUE(ExecuteScript(
    362       app1_wc, "window.localStorage.setItem('testdata', 'ls_app1');"));
    363   ASSERT_TRUE(ExecuteScript(
    364       app2_wc, "window.localStorage.setItem('testdata', 'ls_app2');"));
    365   ASSERT_TRUE(ExecuteScript(
    366       non_app_wc, "window.localStorage.setItem('testdata', 'ls_normal');"));
    367 
    368   const std::string& kRetrieveLocalStorage =
    369       WrapForJavascriptAndExtract("window.localStorage.getItem('testdata')");
    370   std::string result;
    371   ASSERT_TRUE(ExecuteScriptAndExtractString(
    372       app1_wc, kRetrieveLocalStorage.c_str(), &result));
    373   EXPECT_EQ("ls_normal", result);
    374   ASSERT_TRUE(ExecuteScriptAndExtractString(
    375       app2_wc, kRetrieveLocalStorage.c_str(), &result));
    376   EXPECT_EQ("ls_normal", result);
    377   ASSERT_TRUE(ExecuteScriptAndExtractString(
    378       non_app_wc, kRetrieveLocalStorage.c_str(), &result));
    379   EXPECT_EQ("ls_normal", result);
    380 }
    381 
    382 // Test timing out on Windows debug bots.
    383 // http://crbug.com/174926
    384 #if defined(OS_WIN) && !defined(NDEBUG)
    385 #define MAYBE_SubresourceCookieIsolation DISABLED_SubresourceCookieIsolation
    386 #else
    387 #define MAYBE_SubresourceCookieIsolation SubresourceCookieIsolation
    388 #endif  // defined(OS_WIN) && !defined(NDEBUG)
    389 
    390 // Tests that subresource and media requests use the app's cookie store.
    391 // See http://crbug.com/141172.
    392 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_SubresourceCookieIsolation) {
    393   embedded_test_server()->RegisterRequestHandler(
    394       base::Bind(&HandleExpectAndSetCookieRequest, embedded_test_server()));
    395 
    396   host_resolver()->AddRule("*", "127.0.0.1");
    397   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    398 
    399   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
    400 
    401   // The app under test acts on URLs whose host is "localhost",
    402   // so the URLs we navigate to must have host "localhost".
    403   GURL root_url = embedded_test_server()->GetURL("/");
    404   GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
    405   GURL::Replacements replace_host;
    406   std::string host_str("localhost");  // Must stay in scope with replace_host.
    407   replace_host.SetHostStr(host_str);
    408   root_url = root_url.ReplaceComponents(replace_host);
    409   base_url = base_url.ReplaceComponents(replace_host);
    410 
    411   // First set cookies inside and outside the app.
    412   ui_test_utils::NavigateToURLWithDisposition(
    413       browser(), root_url.Resolve("expect-and-set-cookie?set=nonApp%3d1"),
    414       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    415   WebContents* tab0 = browser()->tab_strip_model()->GetWebContentsAt(0);
    416   ASSERT_FALSE(GetInstalledApp(tab0));
    417   ui_test_utils::NavigateToURLWithDisposition(
    418       browser(), base_url.Resolve("app1/main.html"),
    419       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    420   WebContents* tab1 = browser()->tab_strip_model()->GetWebContentsAt(1);
    421   ASSERT_TRUE(GetInstalledApp(tab1));
    422 
    423   // Check that each tab sees its own cookie.
    424   EXPECT_TRUE(HasCookie(tab0, "nonApp=1"));
    425   EXPECT_FALSE(HasCookie(tab0, "app1=3"));
    426   EXPECT_FALSE(HasCookie(tab1, "nonApp=1"));
    427   EXPECT_TRUE(HasCookie(tab1, "app1=3"));
    428 
    429   // Now visit an app page that loads subresources located outside the app.
    430   // For both images and video tags, it loads two URLs:
    431   //  - One will set nonApp{Media,Image}=1 cookies if nonApp=1 is set.
    432   //  - One will set app1{Media,Image}=1 cookies if app1=3 is set.
    433   // We expect only the app's cookies to be present.
    434   // We must wait for the onload event, to allow the subresources to finish.
    435   content::WindowedNotificationObserver observer(
    436       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
    437       content::Source<WebContents>(
    438           browser()->tab_strip_model()->GetActiveWebContents()));
    439   ui_test_utils::NavigateToURLWithDisposition(
    440       browser(), base_url.Resolve("app1/app_subresources.html"),
    441       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    442   observer.Wait();
    443   EXPECT_FALSE(HasCookie(tab1, "nonAppMedia=1"));
    444   EXPECT_TRUE(HasCookie(tab1, "app1Media=1"));
    445   EXPECT_FALSE(HasCookie(tab1, "nonAppImage=1"));
    446   EXPECT_TRUE(HasCookie(tab1, "app1Image=1"));
    447 
    448   // Also create a non-app tab to ensure no new cookies were set in that jar.
    449   ui_test_utils::NavigateToURLWithDisposition(
    450       browser(), root_url,
    451       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    452   WebContents* tab2 = browser()->tab_strip_model()->GetWebContentsAt(2);
    453   EXPECT_FALSE(HasCookie(tab2, "nonAppMedia=1"));
    454   EXPECT_FALSE(HasCookie(tab2, "app1Media=1"));
    455   EXPECT_FALSE(HasCookie(tab2, "nonAppImage=1"));
    456   EXPECT_FALSE(HasCookie(tab2, "app1Image=1"));
    457 }
    458 
    459 // Test is flaky on Windows.
    460 // http://crbug.com/247667
    461 #if defined(OS_WIN)
    462 #define MAYBE_IsolatedAppProcessModel DISABLED_IsolatedAppProcessModel
    463 #else
    464 #define MAYBE_IsolatedAppProcessModel IsolatedAppProcessModel
    465 #endif  // defined(OS_WIN)
    466 
    467 // Tests that isolated apps processes do not render top-level non-app pages.
    468 // This is true even in the case of the OAuth workaround for hosted apps,
    469 // where non-app popups may be kept in the hosted app process.
    470 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_IsolatedAppProcessModel) {
    471   host_resolver()->AddRule("*", "127.0.0.1");
    472   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    473 
    474   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
    475 
    476   // The app under test acts on URLs whose host is "localhost",
    477   // so the URLs we navigate to must have host "localhost".
    478   GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
    479   GURL::Replacements replace_host;
    480   std::string host_str("localhost");  // Must stay in scope with replace_host.
    481   replace_host.SetHostStr(host_str);
    482   base_url = base_url.ReplaceComponents(replace_host);
    483 
    484   // Create three tabs in the isolated app in different ways.
    485   ui_test_utils::NavigateToURLWithDisposition(
    486       browser(), base_url.Resolve("app1/main.html"),
    487       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    488   ui_test_utils::NavigateToURLWithDisposition(
    489       browser(), base_url.Resolve("app1/main.html"),
    490       NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    491   // For the third tab, use window.open to keep it in process with an opener.
    492   OpenWindow(browser()->tab_strip_model()->GetWebContentsAt(0),
    493              base_url.Resolve("app1/main.html"), true, NULL);
    494 
    495   // In a fourth tab, use window.open to a non-app URL.  It should open in a
    496   // separate process, even though this would trigger the OAuth workaround
    497   // for hosted apps (from http://crbug.com/59285).
    498   OpenWindow(browser()->tab_strip_model()->GetWebContentsAt(0),
    499              base_url.Resolve("non_app/main.html"), false, NULL);
    500 
    501   // We should now have four tabs, the first and third sharing a process.
    502   // The second one is an independent instance in a separate process.
    503   ASSERT_EQ(4, browser()->tab_strip_model()->count());
    504   int process_id_0 = browser()->tab_strip_model()->GetWebContentsAt(0)->
    505       GetRenderProcessHost()->GetID();
    506   int process_id_1 = browser()->tab_strip_model()->GetWebContentsAt(1)->
    507       GetRenderProcessHost()->GetID();
    508   EXPECT_NE(process_id_0, process_id_1);
    509   EXPECT_EQ(process_id_0,
    510             browser()->tab_strip_model()->GetWebContentsAt(2)->
    511                 GetRenderProcessHost()->GetID());
    512   EXPECT_NE(process_id_0,
    513             browser()->tab_strip_model()->GetWebContentsAt(3)->
    514                 GetRenderProcessHost()->GetID());
    515 
    516   // Navigating the second tab out of the app should cause a process swap.
    517   const GURL& non_app_url(base_url.Resolve("non_app/main.html"));
    518   NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(1),
    519                      non_app_url);
    520   EXPECT_NE(process_id_1,
    521             browser()->tab_strip_model()->GetWebContentsAt(1)->
    522                 GetRenderProcessHost()->GetID());
    523 }
    524 
    525 // This test no longer passes, since we don't properly isolate sessionStorage
    526 // for isolated apps. This was broken as part of the changes for storage
    527 // partition support for webview tags.
    528 // TODO(nasko): If isolated apps is no longer developed, this test should be
    529 // removed. http://crbug.com/159932
    530 IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_SessionStorage) {
    531   host_resolver()->AddRule("*", "127.0.0.1");
    532   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    533 
    534   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
    535   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
    536 
    537   // The app under test acts on URLs whose host is "localhost",
    538   // so the URLs we navigate to must have host "localhost".
    539   GURL base_url = embedded_test_server()->GetURL("/extensions/isolated_apps/");
    540   GURL::Replacements replace_host;
    541   std::string host_str("localhost");  // Must stay in scope with replace_host.
    542   replace_host.SetHostStr(host_str);
    543   base_url = base_url.ReplaceComponents(replace_host);
    544 
    545   // Enter some state into sessionStorage three times on the same origin, but
    546   // for three URLs that correspond to app1, app2, and a non-isolated site.
    547   ui_test_utils::NavigateToURLWithDisposition(
    548       browser(), base_url.Resolve("app1/main.html"),
    549       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    550   ASSERT_TRUE(ExecuteScript(
    551       browser()->tab_strip_model()->GetWebContentsAt(0),
    552       "window.sessionStorage.setItem('testdata', 'ss_app1');"));
    553 
    554   ui_test_utils::NavigateToURLWithDisposition(
    555       browser(), base_url.Resolve("app2/main.html"),
    556       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    557   ASSERT_TRUE(ExecuteScript(
    558       browser()->tab_strip_model()->GetWebContentsAt(0),
    559       "window.sessionStorage.setItem('testdata', 'ss_app2');"));
    560 
    561   ui_test_utils::NavigateToURLWithDisposition(
    562       browser(), base_url.Resolve("non_app/main.html"),
    563       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    564   ASSERT_TRUE(ExecuteScript(
    565       browser()->tab_strip_model()->GetWebContentsAt(0),
    566       "window.sessionStorage.setItem('testdata', 'ss_normal');"));
    567 
    568   // Now, ensure that the sessionStorage is correctly partitioned, and persists
    569   // when we navigate around all over the dang place.
    570   const std::string& kRetrieveSessionStorage =
    571       WrapForJavascriptAndExtract(
    572           "window.sessionStorage.getItem('testdata') || 'badval'");
    573   std::string result;
    574   ui_test_utils::NavigateToURLWithDisposition(
    575       browser(), base_url.Resolve("app1/main.html"),
    576       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    577   ASSERT_TRUE(ExecuteScriptAndExtractString(
    578       browser()->tab_strip_model()->GetWebContentsAt(0),
    579       kRetrieveSessionStorage.c_str(), &result));
    580   EXPECT_EQ("ss_app1", result);
    581 
    582   ui_test_utils::NavigateToURLWithDisposition(
    583       browser(), base_url.Resolve("app2/main.html"),
    584       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    585   ASSERT_TRUE(ExecuteScriptAndExtractString(
    586       browser()->tab_strip_model()->GetWebContentsAt(0),
    587       kRetrieveSessionStorage.c_str(), &result));
    588   EXPECT_EQ("ss_app2", result);
    589 
    590   ui_test_utils::NavigateToURLWithDisposition(
    591       browser(), base_url.Resolve("non_app/main.html"),
    592       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    593   ASSERT_TRUE(ExecuteScriptAndExtractString(
    594       browser()->tab_strip_model()->GetWebContentsAt(0),
    595       kRetrieveSessionStorage.c_str(), &result));
    596   EXPECT_EQ("ss_normal", result);
    597 }
    598