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/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/url_constants.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/site_instance.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "extensions/browser/process_map.h"
23 #include "extensions/common/switches.h"
24 #include "net/dns/mock_host_resolver.h"
25 #include "net/test/embedded_test_server/embedded_test_server.h"
26 #include "net/test/embedded_test_server/http_response.h"
27 #include "net/test/embedded_test_server/http_request.h"
29 using content::ExecuteScript
;
30 using content::ExecuteScriptAndExtractString
;
31 using content::NavigationController
;
32 using content::WebContents
;
33 using content::RenderViewHost
;
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_parse::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_parse::ExtractQueryKeyValue(
65 query_string
.c_str(), &query
, &key_pos
, &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
));
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
);
88 return scoped_ptr
<net::test_server::HttpResponse
>();
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
.PassAs
<net::test_server::HttpResponse
>();
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 automation_util::GetCookies(contents
->GetURL(), contents
, &value_size
,
108 return actual_cookie
.find(cookie
) != std::string::npos
;
111 const extensions::Extension
* GetInstalledApp(WebContents
* contents
) {
112 const extensions::Extension
* installed_app
= NULL
;
114 Profile::FromBrowserContext(contents
->GetBrowserContext());
115 ExtensionService
* service
= profile
->GetExtensionService();
117 std::set
<std::string
> extension_ids
=
118 extensions::ProcessMap::Get(profile
)->GetExtensionsInProcess(
119 contents
->GetRenderViewHost()->GetProcess()->GetID());
120 for (std::set
<std::string
>::iterator iter
= extension_ids
.begin();
121 iter
!= extension_ids
.end(); ++iter
) {
122 installed_app
= service
->extensions()->GetByID(*iter
);
123 if (installed_app
&& installed_app
->is_app())
124 return installed_app
;
131 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
132 ExtensionBrowserTest::SetUpCommandLine(command_line
);
133 command_line
->AppendSwitch(
134 extensions::switches::kEnableExperimentalExtensionApis
);
140 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, CrossProcessClientRedirect
) {
141 host_resolver()->AddRule("*", "127.0.0.1");
142 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
144 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
145 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app2")));
147 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
148 GURL::Replacements replace_host
;
149 std::string
host_str("localhost"); // Must stay in scope with replace_host.
150 replace_host
.SetHostStr(host_str
);
151 base_url
= base_url
.ReplaceComponents(replace_host
);
152 ui_test_utils::NavigateToURLWithDisposition(
153 browser(), base_url
.Resolve("app1/main.html"),
154 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
157 GURL
redirect_url(embedded_test_server()->GetURL(
158 "/extensions/isolated_apps/app2/redirect.html"));
159 ui_test_utils::NavigateToURLWithDisposition(
160 browser(), redirect_url
,
161 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
164 // If bug fixed, we cannot go back anymore.
165 // If not fixed, we will redirect back to app2 and can go back again.
166 EXPECT_TRUE(chrome::CanGoBack(browser()));
167 chrome::GoBack(browser(), CURRENT_TAB
);
168 EXPECT_TRUE(chrome::CanGoBack(browser()));
169 chrome::GoBack(browser(), CURRENT_TAB
);
170 EXPECT_FALSE(chrome::CanGoBack(browser()));
172 // We also need to test script-initialized navigation (document.location.href)
173 // happened after page finishes loading. This one will also triggered the
174 // willPerformClientRedirect hook in RenderViewImpl but should not replace
175 // the previous history entry.
176 ui_test_utils::NavigateToURLWithDisposition(
177 browser(), base_url
.Resolve("non_app/main.html"),
178 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
180 WebContents
* tab0
= browser()->tab_strip_model()->GetWebContentsAt(1);
182 // Using JavaScript to navigate to app2 page,
183 // after the non_app page has finished loading.
184 content::WindowedNotificationObserver
observer1(
185 content::NOTIFICATION_LOAD_STOP
,
186 content::Source
<NavigationController
>(
187 &browser()->tab_strip_model()->GetActiveWebContents()->
189 std::string script
= base::StringPrintf(
190 "document.location.href=\"%s\";",
191 base_url
.Resolve("app2/main.html").spec().c_str());
192 EXPECT_TRUE(ExecuteScript(tab0
, script
));
195 // This kind of navigation should not replace previous navigation entry.
196 EXPECT_TRUE(chrome::CanGoBack(browser()));
197 chrome::GoBack(browser(), CURRENT_TAB
);
198 EXPECT_FALSE(chrome::CanGoBack(browser()));
201 // Tests that cookies set within an isolated app are not visible to normal
202 // pages or other apps.
204 // TODO(ajwong): Also test what happens if an app spans multiple sites in its
205 // extent. These origins should also be isolated, but still have origin-based
206 // separation as you would expect.
208 // This test is disabled due to being flaky. http://crbug.com/86562
210 #define MAYBE_CookieIsolation DISABLED_CookieIsolation
212 #define MAYBE_CookieIsolation CookieIsolation
214 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, MAYBE_CookieIsolation
) {
215 host_resolver()->AddRule("*", "127.0.0.1");
216 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
218 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
219 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app2")));
221 // The app under test acts on URLs whose host is "localhost",
222 // so the URLs we navigate to must have host "localhost".
223 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
224 GURL::Replacements replace_host
;
225 std::string
host_str("localhost"); // Must stay in scope with replace_host.
226 replace_host
.SetHostStr(host_str
);
227 base_url
= base_url
.ReplaceComponents(replace_host
);
229 ui_test_utils::NavigateToURLWithDisposition(
230 browser(), base_url
.Resolve("app1/main.html"),
231 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
232 ui_test_utils::NavigateToURLWithDisposition(
233 browser(), base_url
.Resolve("app2/main.html"),
234 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
235 ui_test_utils::NavigateToURLWithDisposition(
236 browser(), base_url
.Resolve("non_app/main.html"),
237 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
239 ASSERT_EQ(3, browser()->tab_strip_model()->count());
241 // Ensure first two tabs have installed apps.
242 WebContents
* tab0
= browser()->tab_strip_model()->GetWebContentsAt(0);
243 WebContents
* tab1
= browser()->tab_strip_model()->GetWebContentsAt(1);
244 WebContents
* tab2
= browser()->tab_strip_model()->GetWebContentsAt(2);
245 ASSERT_TRUE(GetInstalledApp(tab0
));
246 ASSERT_TRUE(GetInstalledApp(tab1
));
247 ASSERT_TRUE(!GetInstalledApp(tab2
));
249 // Check that tabs see cannot each other's localStorage even though they are
250 // in the same origin.
251 ASSERT_TRUE(ExecuteScript(
252 tab0
, "window.localStorage.setItem('testdata', 'ls_app1');"));
253 ASSERT_TRUE(ExecuteScript(
254 tab1
, "window.localStorage.setItem('testdata', 'ls_app2');"));
255 ASSERT_TRUE(ExecuteScript(
256 tab2
, "window.localStorage.setItem('testdata', 'ls_normal');"));
258 const std::string
& kRetrieveLocalStorage
=
259 WrapForJavascriptAndExtract(
260 "window.localStorage.getItem('testdata') || 'badval'");
262 ASSERT_TRUE(ExecuteScriptAndExtractString(
263 tab0
, kRetrieveLocalStorage
.c_str(), &result
));
264 EXPECT_EQ("ls_app1", result
);
265 ASSERT_TRUE(ExecuteScriptAndExtractString(
266 tab1
, kRetrieveLocalStorage
.c_str(), &result
));
267 EXPECT_EQ("ls_app2", result
);
268 ASSERT_TRUE(ExecuteScriptAndExtractString(
269 tab2
, kRetrieveLocalStorage
.c_str(), &result
));
270 EXPECT_EQ("ls_normal", result
);
272 // Check that each tab sees its own cookie.
273 EXPECT_TRUE(HasCookie(tab0
, "app1=3"));
274 EXPECT_TRUE(HasCookie(tab1
, "app2=4"));
275 EXPECT_TRUE(HasCookie(tab2
, "normalPage=5"));
277 // Check that app1 tab cannot see the other cookies.
278 EXPECT_FALSE(HasCookie(tab0
, "app2"));
279 EXPECT_FALSE(HasCookie(tab0
, "normalPage"));
281 // Check that app2 tab cannot see the other cookies.
282 EXPECT_FALSE(HasCookie(tab1
, "app1"));
283 EXPECT_FALSE(HasCookie(tab1
, "normalPage"));
285 // Check that normal tab cannot see the other cookies.
286 EXPECT_FALSE(HasCookie(tab2
, "app1"));
287 EXPECT_FALSE(HasCookie(tab2
, "app2"));
289 // Check that the non_app iframe cookie is associated with app1 and not the
290 // normal tab. (For now, iframes are always rendered in their parent
291 // process, even if they aren't in the app manifest.)
292 EXPECT_TRUE(HasCookie(tab0
, "nonAppFrame=6"));
293 EXPECT_FALSE(HasCookie(tab2
, "nonAppFrame"));
295 // Check that isolation persists even if the tab crashes and is reloaded.
296 chrome::SelectNumberedTab(browser(), 0);
297 content::CrashTab(tab0
);
298 content::WindowedNotificationObserver
observer(
299 content::NOTIFICATION_LOAD_STOP
,
300 content::Source
<NavigationController
>(
301 &browser()->tab_strip_model()->GetActiveWebContents()->
303 chrome::Reload(browser(), CURRENT_TAB
);
305 EXPECT_TRUE(HasCookie(tab0
, "app1=3"));
306 EXPECT_FALSE(HasCookie(tab0
, "app2"));
307 EXPECT_FALSE(HasCookie(tab0
, "normalPage"));
311 // This test is disabled due to being flaky. http://crbug.com/145588
312 // Ensure that cookies are not isolated if the isolated apps are not installed.
313 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, DISABLED_NoCookieIsolationWithoutApp
) {
314 host_resolver()->AddRule("*", "127.0.0.1");
315 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
317 // The app under test acts on URLs whose host is "localhost",
318 // so the URLs we navigate to must have host "localhost".
319 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
320 GURL::Replacements replace_host
;
321 std::string
host_str("localhost"); // Must stay in scope with replace_host.
322 replace_host
.SetHostStr(host_str
);
323 base_url
= base_url
.ReplaceComponents(replace_host
);
325 ui_test_utils::NavigateToURLWithDisposition(
326 browser(), base_url
.Resolve("app1/main.html"),
327 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
328 ui_test_utils::NavigateToURLWithDisposition(
329 browser(), base_url
.Resolve("app2/main.html"),
330 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
331 ui_test_utils::NavigateToURLWithDisposition(
332 browser(), base_url
.Resolve("non_app/main.html"),
333 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
335 ASSERT_EQ(3, browser()->tab_strip_model()->count());
337 // Check that tabs see each other's cookies.
338 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
340 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
342 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
344 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
346 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
348 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
350 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
352 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
354 EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
357 // Check that all tabs share the same localStorage if they have the same
359 WebContents
* app1_wc
= browser()->tab_strip_model()->GetWebContentsAt(0);
360 WebContents
* app2_wc
= browser()->tab_strip_model()->GetWebContentsAt(1);
361 WebContents
* non_app_wc
= browser()->tab_strip_model()->GetWebContentsAt(2);
362 ASSERT_TRUE(ExecuteScript(
363 app1_wc
, "window.localStorage.setItem('testdata', 'ls_app1');"));
364 ASSERT_TRUE(ExecuteScript(
365 app2_wc
, "window.localStorage.setItem('testdata', 'ls_app2');"));
366 ASSERT_TRUE(ExecuteScript(
367 non_app_wc
, "window.localStorage.setItem('testdata', 'ls_normal');"));
369 const std::string
& kRetrieveLocalStorage
=
370 WrapForJavascriptAndExtract("window.localStorage.getItem('testdata')");
372 ASSERT_TRUE(ExecuteScriptAndExtractString(
373 app1_wc
, kRetrieveLocalStorage
.c_str(), &result
));
374 EXPECT_EQ("ls_normal", result
);
375 ASSERT_TRUE(ExecuteScriptAndExtractString(
376 app2_wc
, kRetrieveLocalStorage
.c_str(), &result
));
377 EXPECT_EQ("ls_normal", result
);
378 ASSERT_TRUE(ExecuteScriptAndExtractString(
379 non_app_wc
, kRetrieveLocalStorage
.c_str(), &result
));
380 EXPECT_EQ("ls_normal", result
);
383 // Test timing out on Windows debug bots.
384 // http://crbug.com/174926
385 #if defined(OS_WIN) && !defined(NDEBUG)
386 #define MAYBE_SubresourceCookieIsolation DISABLED_SubresourceCookieIsolation
388 #define MAYBE_SubresourceCookieIsolation SubresourceCookieIsolation
389 #endif // defined(OS_WIN) && !defined(NDEBUG)
391 // Tests that subresource and media requests use the app's cookie store.
392 // See http://crbug.com/141172.
393 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, MAYBE_SubresourceCookieIsolation
) {
394 embedded_test_server()->RegisterRequestHandler(
395 base::Bind(&HandleExpectAndSetCookieRequest
, embedded_test_server()));
397 host_resolver()->AddRule("*", "127.0.0.1");
398 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
400 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
402 // The app under test acts on URLs whose host is "localhost",
403 // so the URLs we navigate to must have host "localhost".
404 GURL root_url
= embedded_test_server()->GetURL("/");
405 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
406 GURL::Replacements replace_host
;
407 std::string
host_str("localhost"); // Must stay in scope with replace_host.
408 replace_host
.SetHostStr(host_str
);
409 root_url
= root_url
.ReplaceComponents(replace_host
);
410 base_url
= base_url
.ReplaceComponents(replace_host
);
412 // First set cookies inside and outside the app.
413 ui_test_utils::NavigateToURLWithDisposition(
414 browser(), root_url
.Resolve("expect-and-set-cookie?set=nonApp%3d1"),
415 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
416 WebContents
* tab0
= browser()->tab_strip_model()->GetWebContentsAt(0);
417 ASSERT_FALSE(GetInstalledApp(tab0
));
418 ui_test_utils::NavigateToURLWithDisposition(
419 browser(), base_url
.Resolve("app1/main.html"),
420 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
421 WebContents
* tab1
= browser()->tab_strip_model()->GetWebContentsAt(1);
422 ASSERT_TRUE(GetInstalledApp(tab1
));
424 // Check that each tab sees its own cookie.
425 EXPECT_TRUE(HasCookie(tab0
, "nonApp=1"));
426 EXPECT_FALSE(HasCookie(tab0
, "app1=3"));
427 EXPECT_FALSE(HasCookie(tab1
, "nonApp=1"));
428 EXPECT_TRUE(HasCookie(tab1
, "app1=3"));
430 // Now visit an app page that loads subresources located outside the app.
431 // For both images and video tags, it loads two URLs:
432 // - One will set nonApp{Media,Image}=1 cookies if nonApp=1 is set.
433 // - One will set app1{Media,Image}=1 cookies if app1=3 is set.
434 // We expect only the app's cookies to be present.
435 // We must wait for the onload event, to allow the subresources to finish.
436 content::WindowedNotificationObserver
observer(
437 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
438 content::Source
<WebContents
>(
439 browser()->tab_strip_model()->GetActiveWebContents()));
440 ui_test_utils::NavigateToURLWithDisposition(
441 browser(), base_url
.Resolve("app1/app_subresources.html"),
442 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
444 EXPECT_FALSE(HasCookie(tab1
, "nonAppMedia=1"));
445 EXPECT_TRUE(HasCookie(tab1
, "app1Media=1"));
446 EXPECT_FALSE(HasCookie(tab1
, "nonAppImage=1"));
447 EXPECT_TRUE(HasCookie(tab1
, "app1Image=1"));
449 // Also create a non-app tab to ensure no new cookies were set in that jar.
450 ui_test_utils::NavigateToURLWithDisposition(
452 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
453 WebContents
* tab2
= browser()->tab_strip_model()->GetWebContentsAt(2);
454 EXPECT_FALSE(HasCookie(tab2
, "nonAppMedia=1"));
455 EXPECT_FALSE(HasCookie(tab2
, "app1Media=1"));
456 EXPECT_FALSE(HasCookie(tab2
, "nonAppImage=1"));
457 EXPECT_FALSE(HasCookie(tab2
, "app1Image=1"));
460 // Test is flaky on Windows.
461 // http://crbug.com/247667
463 #define MAYBE_IsolatedAppProcessModel DISABLED_IsolatedAppProcessModel
465 #define MAYBE_IsolatedAppProcessModel IsolatedAppProcessModel
466 #endif // defined(OS_WIN)
468 // Tests that isolated apps processes do not render top-level non-app pages.
469 // This is true even in the case of the OAuth workaround for hosted apps,
470 // where non-app popups may be kept in the hosted app process.
471 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, MAYBE_IsolatedAppProcessModel
) {
472 host_resolver()->AddRule("*", "127.0.0.1");
473 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
475 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
477 // The app under test acts on URLs whose host is "localhost",
478 // so the URLs we navigate to must have host "localhost".
479 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
480 GURL::Replacements replace_host
;
481 std::string
host_str("localhost"); // Must stay in scope with replace_host.
482 replace_host
.SetHostStr(host_str
);
483 base_url
= base_url
.ReplaceComponents(replace_host
);
485 // Create three tabs in the isolated app in different ways.
486 ui_test_utils::NavigateToURLWithDisposition(
487 browser(), base_url
.Resolve("app1/main.html"),
488 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
489 ui_test_utils::NavigateToURLWithDisposition(
490 browser(), base_url
.Resolve("app1/main.html"),
491 NEW_FOREGROUND_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
492 // For the third tab, use window.open to keep it in process with an opener.
493 OpenWindow(browser()->tab_strip_model()->GetWebContentsAt(0),
494 base_url
.Resolve("app1/main.html"), true, NULL
);
496 // In a fourth tab, use window.open to a non-app URL. It should open in a
497 // separate process, even though this would trigger the OAuth workaround
498 // for hosted apps (from http://crbug.com/59285).
499 OpenWindow(browser()->tab_strip_model()->GetWebContentsAt(0),
500 base_url
.Resolve("non_app/main.html"), false, NULL
);
502 // We should now have four tabs, the first and third sharing a process.
503 // The second one is an independent instance in a separate process.
504 ASSERT_EQ(4, browser()->tab_strip_model()->count());
505 int process_id_0
= browser()->tab_strip_model()->GetWebContentsAt(0)->
506 GetRenderProcessHost()->GetID();
507 int process_id_1
= browser()->tab_strip_model()->GetWebContentsAt(1)->
508 GetRenderProcessHost()->GetID();
509 EXPECT_NE(process_id_0
, process_id_1
);
510 EXPECT_EQ(process_id_0
,
511 browser()->tab_strip_model()->GetWebContentsAt(2)->
512 GetRenderProcessHost()->GetID());
513 EXPECT_NE(process_id_0
,
514 browser()->tab_strip_model()->GetWebContentsAt(3)->
515 GetRenderProcessHost()->GetID());
517 // Navigating the second tab out of the app should cause a process swap.
518 const GURL
& non_app_url(base_url
.Resolve("non_app/main.html"));
519 NavigateInRenderer(browser()->tab_strip_model()->GetWebContentsAt(1),
521 EXPECT_NE(process_id_1
,
522 browser()->tab_strip_model()->GetWebContentsAt(1)->
523 GetRenderProcessHost()->GetID());
526 // This test no longer passes, since we don't properly isolate sessionStorage
527 // for isolated apps. This was broken as part of the changes for storage
528 // partition support for webview tags.
529 // TODO(nasko): If isolated apps is no longer developed, this test should be
530 // removed. http://crbug.com/159932
531 IN_PROC_BROWSER_TEST_F(IsolatedAppTest
, DISABLED_SessionStorage
) {
532 host_resolver()->AddRule("*", "127.0.0.1");
533 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
535 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app1")));
536 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("isolated_apps/app2")));
538 // The app under test acts on URLs whose host is "localhost",
539 // so the URLs we navigate to must have host "localhost".
540 GURL base_url
= embedded_test_server()->GetURL("/extensions/isolated_apps/");
541 GURL::Replacements replace_host
;
542 std::string
host_str("localhost"); // Must stay in scope with replace_host.
543 replace_host
.SetHostStr(host_str
);
544 base_url
= base_url
.ReplaceComponents(replace_host
);
546 // Enter some state into sessionStorage three times on the same origin, but
547 // for three URLs that correspond to app1, app2, and a non-isolated site.
548 ui_test_utils::NavigateToURLWithDisposition(
549 browser(), base_url
.Resolve("app1/main.html"),
550 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
551 ASSERT_TRUE(ExecuteScript(
552 browser()->tab_strip_model()->GetWebContentsAt(0),
553 "window.sessionStorage.setItem('testdata', 'ss_app1');"));
555 ui_test_utils::NavigateToURLWithDisposition(
556 browser(), base_url
.Resolve("app2/main.html"),
557 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
558 ASSERT_TRUE(ExecuteScript(
559 browser()->tab_strip_model()->GetWebContentsAt(0),
560 "window.sessionStorage.setItem('testdata', 'ss_app2');"));
562 ui_test_utils::NavigateToURLWithDisposition(
563 browser(), base_url
.Resolve("non_app/main.html"),
564 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
565 ASSERT_TRUE(ExecuteScript(
566 browser()->tab_strip_model()->GetWebContentsAt(0),
567 "window.sessionStorage.setItem('testdata', 'ss_normal');"));
569 // Now, ensure that the sessionStorage is correctly partitioned, and persists
570 // when we navigate around all over the dang place.
571 const std::string
& kRetrieveSessionStorage
=
572 WrapForJavascriptAndExtract(
573 "window.sessionStorage.getItem('testdata') || 'badval'");
575 ui_test_utils::NavigateToURLWithDisposition(
576 browser(), base_url
.Resolve("app1/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_app1", result
);
583 ui_test_utils::NavigateToURLWithDisposition(
584 browser(), base_url
.Resolve("app2/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_app2", result
);
591 ui_test_utils::NavigateToURLWithDisposition(
592 browser(), base_url
.Resolve("non_app/main.html"),
593 CURRENT_TAB
, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
594 ASSERT_TRUE(ExecuteScriptAndExtractString(
595 browser()->tab_strip_model()->GetWebContentsAt(0),
596 kRetrieveSessionStorage
.c_str(), &result
));
597 EXPECT_EQ("ss_normal", result
);