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.
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"
27 using content::ExecuteScript
;
28 using content::ExecuteScriptAndExtractString
;
29 using content::NavigationController
;
30 using content::RenderViewHost
;
31 using content::WebContents
;
33 namespace extensions
{
37 std::string
WrapForJavascriptAndExtract(const char* javascript_expression
) {
38 return std::string("window.domAutomationController.send(") +
39 javascript_expression
+ ")";
42 scoped_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
>();
48 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
49 new net::test_server::BasicHttpResponse
);
50 http_response
->set_code(net::HTTP_OK
);
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
;
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
,
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
));
71 net::UnescapeURLComponent(escaped_key
,
72 net::UnescapeRule::NORMAL
|
73 net::UnescapeRule::SPACES
|
74 net::UnescapeRule::URL_SPECIAL_CHARS
);
77 net::UnescapeURLComponent(escaped_value
,
78 net::UnescapeRule::NORMAL
|
79 net::UnescapeRule::SPACES
|
80 net::UnescapeRule::URL_SPECIAL_CHARS
);
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
);
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
]);
97 return http_response
.Pass();
100 class IsolatedAppTest
: public ExtensionBrowserTest
{
102 // Returns whether the given tab's current URL has the given cookie.
103 bool WARN_UNUSED_RESULT
HasCookie(WebContents
* contents
, std::string cookie
) {
105 std::string actual_cookie
;
106 ui_test_utils::GetCookies(contents
->GetURL(), contents
, &value_size
,
108 return actual_cookie
.find(cookie
) != std::string::npos
;
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
;
128 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
129 ExtensionBrowserTest::SetUpCommandLine(command_line
);
130 command_line
->AppendSwitch(switches::kEnableExperimentalExtensionApis
);
134 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, CrossProcessClientRedirect
) {
135 host_resolver()->AddRule("*", "127.0.0.1");
136 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
138 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
139 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app2")));
141 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
142 GURL::Replacements replace_host
;
143 replace_host
.SetHostStr("localhost");
144 base_url
= base_url
.ReplaceComponents(replace_host
);
145 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app1/main.html"));
148 GURL
redirect_url(embedded_test_server()->GetURL(
149 "/extensions/isolated_apps/app2/redirect.html"));
150 ui_test_utils::NavigateToURL(browser(), redirect_url
);
153 // If bug fixed, we cannot go back anymore.
154 // If not fixed, we will redirect back to app2 and can go back again.
155 EXPECT_TRUE(chrome::CanGoBack(browser()));
156 chrome::GoBack(browser(), CURRENT_TAB
);
157 EXPECT_TRUE(chrome::CanGoBack(browser()));
158 chrome::GoBack(browser(), CURRENT_TAB
);
159 EXPECT_FALSE(chrome::CanGoBack(browser()));
161 // We also need to test script-initialized navigation (document.location.href)
162 // happened after page finishes loading. This one will also triggered the
163 // willPerformClientRedirect hook in RenderViewImpl but should not replace
164 // the previous history entry.
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
);
169 WebContents
* tab0
= browser()->tab_strip_model()->GetWebContentsAt(1);
171 // Using JavaScript to navigate to app2 page,
172 // after the non_app page has finished loading.
173 content::WindowedNotificationObserver
observer1(
174 content::NOTIFICATION_LOAD_STOP
,
175 content::Source
<NavigationController
>(
176 &browser()->tab_strip_model()->GetActiveWebContents()->
178 std::string script
= base::StringPrintf(
179 "document.location.href=\"%s\";",
180 base_url
.Resolve("app2/main.html").spec().c_str());
181 EXPECT_TRUE(ExecuteScript(tab0
, script
));
184 // This kind of navigation should not replace previous navigation entry.
185 EXPECT_TRUE(chrome::CanGoBack(browser()));
186 chrome::GoBack(browser(), CURRENT_TAB
);
187 EXPECT_FALSE(chrome::CanGoBack(browser()));
190 // Tests that cookies set within an isolated app are not visible to normal
191 // pages or other apps.
193 // TODO(ajwong): Also test what happens if an app spans multiple sites in its
194 // extent. These origins should also be isolated, but still have origin-based
195 // separation as you would expect.
197 // This test is disabled due to being flaky. http://crbug.com/86562
199 #define MAYBE_CookieIsolation DISABLED_CookieIsolation
201 #define MAYBE_CookieIsolation CookieIsolation
203 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, MAYBE_CookieIsolation
) {
204 host_resolver()->AddRule("*", "127.0.0.1");
205 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
207 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
208 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app2")));
210 // The app under test acts on URLs whose host is "localhost",
211 // so the URLs we navigate to must have host "localhost".
212 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
213 GURL::Replacements replace_host
;
214 replace_host
.SetHostStr("localhost");
215 base_url
= base_url
.ReplaceComponents(replace_host
);
217 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app1/main.html"));
218 ui_test_utils::NavigateToURLWithDisposition(
219 browser(), base_url
.Resolve("app2/main.html"),
220 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
221 ui_test_utils::NavigateToURLWithDisposition(
222 browser(), base_url
.Resolve("non_app/main.html"),
223 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
225 ASSERT_EQ(3, browser()->tab_strip_model()->count());
227 // Ensure first two tabs have installed apps.
228 WebContents
* tab0
= browser()->tab_strip_model()->GetWebContentsAt(0);
229 WebContents
* tab1
= browser()->tab_strip_model()->GetWebContentsAt(1);
230 WebContents
* tab2
= browser()->tab_strip_model()->GetWebContentsAt(2);
231 ASSERT_TRUE(GetInstalledApp(tab0
));
232 ASSERT_TRUE(GetInstalledApp(tab1
));
233 ASSERT_TRUE(!GetInstalledApp(tab2
));
235 // Check that tabs see cannot each other's localStorage even though they are
236 // in the same origin.
237 ASSERT_TRUE(ExecuteScript(
238 tab0
, "window.localStorage.setItem('testdata', 'ls_app1');"));
239 ASSERT_TRUE(ExecuteScript(
240 tab1
, "window.localStorage.setItem('testdata', 'ls_app2');"));
241 ASSERT_TRUE(ExecuteScript(
242 tab2
, "window.localStorage.setItem('testdata', 'ls_normal');"));
244 const std::string
& kRetrieveLocalStorage
=
245 WrapForJavascriptAndExtract(
246 "window.localStorage.getItem('testdata') || 'badval'");
248 ASSERT_TRUE(ExecuteScriptAndExtractString(
249 tab0
, kRetrieveLocalStorage
.c_str(), &result
));
250 EXPECT_EQ("ls_app1", result
);
251 ASSERT_TRUE(ExecuteScriptAndExtractString(
252 tab1
, kRetrieveLocalStorage
.c_str(), &result
));
253 EXPECT_EQ("ls_app2", result
);
254 ASSERT_TRUE(ExecuteScriptAndExtractString(
255 tab2
, kRetrieveLocalStorage
.c_str(), &result
));
256 EXPECT_EQ("ls_normal", result
);
258 // Check that each tab sees its own cookie.
259 EXPECT_TRUE(HasCookie(tab0
, "app1=3"));
260 EXPECT_TRUE(HasCookie(tab1
, "app2=4"));
261 EXPECT_TRUE(HasCookie(tab2
, "normalPage=5"));
263 // Check that app1 tab cannot see the other cookies.
264 EXPECT_FALSE(HasCookie(tab0
, "app2"));
265 EXPECT_FALSE(HasCookie(tab0
, "normalPage"));
267 // Check that app2 tab cannot see the other cookies.
268 EXPECT_FALSE(HasCookie(tab1
, "app1"));
269 EXPECT_FALSE(HasCookie(tab1
, "normalPage"));
271 // Check that normal tab cannot see the other cookies.
272 EXPECT_FALSE(HasCookie(tab2
, "app1"));
273 EXPECT_FALSE(HasCookie(tab2
, "app2"));
275 // Check that the non_app iframe cookie is associated with app1 and not the
276 // normal tab. (For now, iframes are always rendered in their parent
277 // process, even if they aren't in the app manifest.)
278 EXPECT_TRUE(HasCookie(tab0
, "nonAppFrame=6"));
279 EXPECT_FALSE(HasCookie(tab2
, "nonAppFrame"));
281 // Check that isolation persists even if the tab crashes and is reloaded.
282 chrome::SelectNumberedTab(browser(), 0);
283 content::CrashTab(tab0
);
284 content::WindowedNotificationObserver
observer(
285 content::NOTIFICATION_LOAD_STOP
,
286 content::Source
<NavigationController
>(
287 &browser()->tab_strip_model()->GetActiveWebContents()->
289 chrome::Reload(browser(), CURRENT_TAB
);
291 EXPECT_TRUE(HasCookie(tab0
, "app1=3"));
292 EXPECT_FALSE(HasCookie(tab0
, "app2"));
293 EXPECT_FALSE(HasCookie(tab0
, "normalPage"));
296 // This test is disabled due to being flaky. http://crbug.com/145588
297 // Ensure that cookies are not isolated if the isolated apps are not installed.
298 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, DISABLED_NoCookieIsolationWithoutApp
) {
299 host_resolver()->AddRule("*", "127.0.0.1");
300 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
302 // The app under test acts on URLs whose host is "localhost",
303 // so the URLs we navigate to must have host "localhost".
304 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
305 GURL::Replacements replace_host
;
306 replace_host
.SetHostStr("localhost");
307 base_url
= base_url
.ReplaceComponents(replace_host
);
309 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app1/main.html"));
310 ui_test_utils::NavigateToURLWithDisposition(
311 browser(), base_url
.Resolve("app2/main.html"),
312 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
313 ui_test_utils::NavigateToURLWithDisposition(
314 browser(), base_url
.Resolve("non_app/main.html"),
315 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
317 ASSERT_EQ(3, browser()->tab_strip_model()->count());
319 // Check that tabs see each other's cookies.
320 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
322 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
324 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
326 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
328 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
330 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
332 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
334 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
336 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
339 // Check that all tabs share the same localStorage if they have the same
341 WebContents
* app1_wc
= browser()->tab_strip_model()->GetWebContentsAt(0);
342 WebContents
* app2_wc
= browser()->tab_strip_model()->GetWebContentsAt(1);
343 WebContents
* non_app_wc
= browser()->tab_strip_model()->GetWebContentsAt(2);
344 ASSERT_TRUE(ExecuteScript(
345 app1_wc
, "window.localStorage.setItem('testdata', 'ls_app1');"));
346 ASSERT_TRUE(ExecuteScript(
347 app2_wc
, "window.localStorage.setItem('testdata', 'ls_app2');"));
348 ASSERT_TRUE(ExecuteScript(
349 non_app_wc
, "window.localStorage.setItem('testdata', 'ls_normal');"));
351 const std::string
& kRetrieveLocalStorage
=
352 WrapForJavascriptAndExtract("window.localStorage.getItem('testdata')");
354 ASSERT_TRUE(ExecuteScriptAndExtractString(
355 app1_wc
, kRetrieveLocalStorage
.c_str(), &result
));
356 EXPECT_EQ("ls_normal", result
);
357 ASSERT_TRUE(ExecuteScriptAndExtractString(
358 app2_wc
, kRetrieveLocalStorage
.c_str(), &result
));
359 EXPECT_EQ("ls_normal", result
);
360 ASSERT_TRUE(ExecuteScriptAndExtractString(
361 non_app_wc
, kRetrieveLocalStorage
.c_str(), &result
));
362 EXPECT_EQ("ls_normal", result
);
365 // http://crbug.com/174926
366 #if (defined(OS_WIN) && !defined(NDEBUG)) || defined(OS_MACOSX)
367 #define MAYBE_SubresourceCookieIsolation DISABLED_SubresourceCookieIsolation
369 #define MAYBE_SubresourceCookieIsolation SubresourceCookieIsolation
370 #endif // (defined(OS_WIN) && !defined(NDEBUG)) || defined(OS_MACOSX)
372 // Tests that subresource and media requests use the app's cookie store.
373 // See http://crbug.com/141172.
374 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, MAYBE_SubresourceCookieIsolation
) {
375 embedded_test_server()->RegisterRequestHandler(
376 base::Bind(&HandleExpectAndSetCookieRequest
, embedded_test_server()));
378 host_resolver()->AddRule("*", "127.0.0.1");
379 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
381 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
383 // The app under test acts on URLs whose host is "localhost",
384 // so the URLs we navigate to must have host "localhost".
385 GURL root_url
= embedded_test_server()->GetURL("/");
386 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
387 GURL::Replacements replace_host
;
388 replace_host
.SetHostStr("localhost");
389 root_url
= root_url
.ReplaceComponents(replace_host
);
390 base_url
= base_url
.ReplaceComponents(replace_host
);
392 // First set cookies inside and outside the app.
393 ui_test_utils::NavigateToURL(
394 browser(), root_url
.Resolve("expect-and-set-cookie?set=nonApp%3d1"));
395 WebContents
* tab0
= browser()->tab_strip_model()->GetWebContentsAt(0);
396 ASSERT_FALSE(GetInstalledApp(tab0
));
397 ui_test_utils::NavigateToURLWithDisposition(
398 browser(), base_url
.Resolve("app1/main.html"),
399 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
400 WebContents
* tab1
= browser()->tab_strip_model()->GetWebContentsAt(1);
401 ASSERT_TRUE(GetInstalledApp(tab1
));
403 // Check that each tab sees its own cookie.
404 EXPECT_TRUE(HasCookie(tab0
, "nonApp=1"));
405 EXPECT_FALSE(HasCookie(tab0
, "app1=3"));
406 EXPECT_FALSE(HasCookie(tab1
, "nonApp=1"));
407 EXPECT_TRUE(HasCookie(tab1
, "app1=3"));
409 // Now visit an app page that loads subresources located outside the app.
410 // For both images and video tags, it loads two URLs:
411 // - One will set nonApp{Media,Image}=1 cookies if nonApp=1 is set.
412 // - One will set app1{Media,Image}=1 cookies if app1=3 is set.
413 // We expect only the app's cookies to be present.
414 // We must wait for the onload event, to allow the subresources to finish.
415 content::WindowedNotificationObserver
observer(
416 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
417 content::Source
<WebContents
>(
418 browser()->tab_strip_model()->GetActiveWebContents()));
419 ui_test_utils::NavigateToURL(
420 browser(), base_url
.Resolve("app1/app_subresources.html"));
422 EXPECT_FALSE(HasCookie(tab1
, "nonAppMedia=1"));
423 EXPECT_TRUE(HasCookie(tab1
, "app1Media=1"));
424 EXPECT_FALSE(HasCookie(tab1
, "nonAppImage=1"));
425 EXPECT_TRUE(HasCookie(tab1
, "app1Image=1"));
427 // Also create a non-app tab to ensure no new cookies were set in that jar.
428 ui_test_utils::NavigateToURLWithDisposition(
430 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
431 WebContents
* tab2
= browser()->tab_strip_model()->GetWebContentsAt(2);
432 EXPECT_FALSE(HasCookie(tab2
, "nonAppMedia=1"));
433 EXPECT_FALSE(HasCookie(tab2
, "app1Media=1"));
434 EXPECT_FALSE(HasCookie(tab2
, "nonAppImage=1"));
435 EXPECT_FALSE(HasCookie(tab2
, "app1Image=1"));
438 // Test is flaky on Windows.
439 // http://crbug.com/247667
441 #define MAYBE_IsolatedAppProcessModel DISABLED_IsolatedAppProcessModel
443 #define MAYBE_IsolatedAppProcessModel IsolatedAppProcessModel
444 #endif // defined(OS_WIN)
446 // Tests that isolated apps processes do not render top-level non-app pages.
447 // This is true even in the case of the OAuth workaround for hosted apps,
448 // where non-app popups may be kept in the hosted app process.
449 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, MAYBE_IsolatedAppProcessModel
) {
450 host_resolver()->AddRule("*", "127.0.0.1");
451 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
453 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
455 // The app under test acts on URLs whose host is "localhost",
456 // so the URLs we navigate to must have host "localhost".
457 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
458 GURL::Replacements replace_host
;
459 replace_host
.SetHostStr("localhost");
460 base_url
= base_url
.ReplaceComponents(replace_host
);
462 // Create three tabs in the isolated app in different ways.
463 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app1/main.html"));
464 ui_test_utils::NavigateToURLWithDisposition(
465 browser(), base_url
.Resolve("app1/main.html"),
466 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
467 // For the third tab, use window.open to keep it in process with an opener.
468 OpenWindow(browser()->tab_strip_model()->GetWebContentsAt(0),
469 base_url
.Resolve("app1/main.html"), true, NULL
);
471 // In a fourth tab, use window.open to a non-app URL. It should open in a
472 // separate process, even though this would trigger the OAuth workaround
473 // for hosted apps (from http://crbug.com/59285).
474 OpenWindow(browser()->tab_strip_model()->GetWebContentsAt(0),
475 base_url
.Resolve("non_app/main.html"), false, NULL
);
477 // We should now have four tabs, the first and third sharing a process.
478 // The second one is an independent instance in a separate process.
479 ASSERT_EQ(4, browser()->tab_strip_model()->count());
480 int process_id_0
= browser()->tab_strip_model()->GetWebContentsAt(0)->
481 GetRenderProcessHost()->GetID();
482 int process_id_1
= browser()->tab_strip_model()->GetWebContentsAt(1)->
483 GetRenderProcessHost()->GetID();
484 EXPECT_NE(process_id_0
, process_id_1
);
485 EXPECT_EQ(process_id_0
,
486 browser()->tab_strip_model()->GetWebContentsAt(2)->
487 GetRenderProcessHost()->GetID());
488 EXPECT_NE(process_id_0
,
489 browser()->tab_strip_model()->GetWebContentsAt(3)->
490 GetRenderProcessHost()->GetID());
492 // Navigating the second tab out of the app should cause a process swap.
493 const GURL
& non_app_url(base_url
.Resolve("non_app/main.html"));
494 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(1),
496 EXPECT_NE(process_id_1
,
497 browser()->tab_strip_model()->GetWebContentsAt(1)->
498 GetRenderProcessHost()->GetID());
501 // This test no longer passes, since we don't properly isolate sessionStorage
502 // for isolated apps. This was broken as part of the changes for storage
503 // partition support for webview tags.
504 // TODO(nasko): If isolated apps is no longer developed, this test should be
505 // removed. http://crbug.com/159932
506 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, DISABLED_SessionStorage
) {
507 host_resolver()->AddRule("*", "127.0.0.1");
508 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
510 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
511 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app2")));
513 // The app under test acts on URLs whose host is "localhost",
514 // so the URLs we navigate to must have host "localhost".
515 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
516 GURL::Replacements replace_host
;
517 replace_host
.SetHostStr("localhost");
518 base_url
= base_url
.ReplaceComponents(replace_host
);
520 // Enter some state into sessionStorage three times on the same origin, but
521 // for three URLs that correspond to app1, app2, and a non-isolated site.
522 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app1/main.html"));
523 ASSERT_TRUE(ExecuteScript(
524 browser()->tab_strip_model()->GetWebContentsAt(0),
525 "window.sessionStorage.setItem('testdata', 'ss_app1');"));
527 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app2/main.html"));
528 ASSERT_TRUE(ExecuteScript(
529 browser()->tab_strip_model()->GetWebContentsAt(0),
530 "window.sessionStorage.setItem('testdata', 'ss_app2');"));
532 ui_test_utils::NavigateToURL(
533 browser(), base_url
.Resolve("non_app/main.html"));
534 ASSERT_TRUE(ExecuteScript(
535 browser()->tab_strip_model()->GetWebContentsAt(0),
536 "window.sessionStorage.setItem('testdata', 'ss_normal');"));
538 // Now, ensure that the sessionStorage is correctly partitioned, and persists
539 // when we navigate around all over the dang place.
540 const std::string
& kRetrieveSessionStorage
=
541 WrapForJavascriptAndExtract(
542 "window.sessionStorage.getItem('testdata') || 'badval'");
544 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app1/main.html"));
545 ASSERT_TRUE(ExecuteScriptAndExtractString(
546 browser()->tab_strip_model()->GetWebContentsAt(0),
547 kRetrieveSessionStorage
.c_str(), &result
));
548 EXPECT_EQ("ss_app1", result
);
550 ui_test_utils::NavigateToURL(browser(), base_url
.Resolve("app2/main.html"));
551 ASSERT_TRUE(ExecuteScriptAndExtractString(
552 browser()->tab_strip_model()->GetWebContentsAt(0),
553 kRetrieveSessionStorage
.c_str(), &result
));
554 EXPECT_EQ("ss_app2", result
);
556 ui_test_utils::NavigateToURL(
557 browser(), base_url
.Resolve("non_app/main.html"));
558 ASSERT_TRUE(ExecuteScriptAndExtractString(
559 browser()->tab_strip_model()->GetWebContentsAt(0),
560 kRetrieveSessionStorage
.c_str(), &result
));
561 EXPECT_EQ("ss_normal", result
);
566 } // namespace extensions