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
27 using content::ExecuteScript;
28 using content::ExecuteScriptAndExtractString;
29 using content::NavigationController;
30 using content::RenderViewHost;
31 using content::WebContents;
32
33 namespace extensions {
34
35 namespace {
36
WrapForJavascriptAndExtract(const char * javascript_expression)37 std::string WrapForJavascriptAndExtract(const char* javascript_expression) {
38 return std::string("window.domAutomationController.send(") +
39 javascript_expression + ")";
40 }
41
HandleExpectAndSetCookieRequest(const net::test_server::EmbeddedTestServer * test_server,const net::test_server::HttpRequest & request)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>();
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
100 class IsolatedAppTest : public ExtensionBrowserTest {
101 public:
102 // Returns whether the given tab's current URL has the given cookie.
HasCookie(WebContents * contents,std::string 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
GetInstalledApp(WebContents * contents)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:
SetUpCommandLine(base::CommandLine * command_line)128 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
129 ExtensionBrowserTest::SetUpCommandLine(command_line);
130 command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
131 }
132 };
133
IN_PROC_BROWSER_TEST_F(IsolatedAppTest,CrossProcessClientRedirect)134 IN_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
IN_PROC_BROWSER_TEST_F(IsolatedAppTest,MAYBE_CookieIsolation)208 IN_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.
IN_PROC_BROWSER_TEST_F(IsolatedAppTest,DISABLED_NoCookieIsolationWithoutApp)306 IN_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.
IN_PROC_BROWSER_TEST_F(IsolatedAppTest,MAYBE_SubresourceCookieIsolation)385 IN_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.
IN_PROC_BROWSER_TEST_F(IsolatedAppTest,MAYBE_IsolatedAppProcessModel)463 IN_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
IN_PROC_BROWSER_TEST_F(IsolatedAppTest,DISABLED_SessionStorage)523 IN_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