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