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