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