isolated_app_browsertest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/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"
28
29using content::ExecuteScript;
30using content::ExecuteScriptAndExtractString;
31using content::NavigationController;
32using content::WebContents;
33using content::RenderViewHost;
34
35namespace {
36
37std::string WrapForJavascriptAndExtract(const char* javascript_expression) {
38  return std::string("window.domAutomationController.send(") +
39      javascript_expression + ")";
40}
41
42scoped_ptr<net::test_server::HttpResponse> HandleExpectAndSetCookieRequest(
43    const net::test_server::EmbeddedTestServer* test_server,
44    const net::test_server::HttpRequest& request) {
45  if (!StartsWithASCII(request.relative_url, "/expect-and-set-cookie?", true))
46    return scoped_ptr<net::test_server::HttpResponse>();
47
48  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
49      new net::test_server::BasicHttpResponse);
50  http_response->set_code(net::HTTP_OK);
51
52  std::string request_cookies;
53  std::map<std::string, std::string>::const_iterator it =
54      request.headers.find("Cookie");
55  if (it != request.headers.end())
56    request_cookies = it->second;
57
58  size_t query_string_pos = request.relative_url.find('?');
59  std::string query_string =
60      request.relative_url.substr(query_string_pos + 1);
61  url_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));
69
70    std::string key =
71        net::UnescapeURLComponent(escaped_key,
72                                  net::UnescapeRule::NORMAL |
73                                  net::UnescapeRule::SPACES |
74                                  net::UnescapeRule::URL_SPECIAL_CHARS);
75
76    std::string value =
77        net::UnescapeURLComponent(escaped_value,
78                                  net::UnescapeRule::NORMAL |
79                                  net::UnescapeRule::SPACES |
80                                  net::UnescapeRule::URL_SPECIAL_CHARS);
81
82    if (key == "expect") {
83      if (request_cookies.find(value) == std::string::npos)
84        expectations_satisfied = false;
85    } else if (key == "set") {
86      cookies_to_set.push_back(value);
87    } else {
88      return scoped_ptr<net::test_server::HttpResponse>();
89    }
90  }
91
92  if (expectations_satisfied) {
93    for (size_t i = 0; i < cookies_to_set.size(); i++)
94      http_response->AddCustomHeader("Set-Cookie", cookies_to_set[i]);
95  }
96
97  return http_response.PassAs<net::test_server::HttpResponse>();
98}
99
100class IsolatedAppTest : public ExtensionBrowserTest {
101 public:
102  // Returns whether the given tab's current URL has the given cookie.
103  bool WARN_UNUSED_RESULT HasCookie(WebContents* contents, std::string cookie) {
104    int value_size;
105    std::string actual_cookie;
106    automation_util::GetCookies(contents->GetURL(), contents, &value_size,
107                                &actual_cookie);
108    return actual_cookie.find(cookie) != std::string::npos;
109  }
110
111  const extensions::Extension* GetInstalledApp(WebContents* contents) {
112    const extensions::Extension* installed_app = NULL;
113    Profile* profile =
114        Profile::FromBrowserContext(contents->GetBrowserContext());
115    ExtensionService* service = profile->GetExtensionService();
116    if (service) {
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;
125      }
126    }
127    return NULL;
128  }
129
130 private:
131  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
132    ExtensionBrowserTest::SetUpCommandLine(command_line);
133    command_line->AppendSwitch(
134        extensions::switches::kEnableExperimentalExtensionApis);
135  }
136};
137
138}  // namespace
139
140IN_PROC_BROWSER_TEST_F(IsolatedAppTest, CrossProcessClientRedirect) {
141  host_resolver()->AddRule("*", "127.0.0.1");
142  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
143
144  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
145  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
146
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);
155
156  // Redirect to app2.
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);
162
163  // Go back twice.
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()));
171
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);
179
180  WebContents* tab0 = browser()->tab_strip_model()->GetWebContentsAt(1);
181
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()->
188              GetController()));
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));
193  observer1.Wait();
194
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()));
199}
200
201// Tests that cookies set within an isolated app are not visible to normal
202// pages or other apps.
203//
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.
207//
208// This test is disabled due to being flaky. http://crbug.com/86562
209#if defined(OS_WIN)
210#define MAYBE_CookieIsolation DISABLED_CookieIsolation
211#else
212#define MAYBE_CookieIsolation CookieIsolation
213#endif
214IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_CookieIsolation) {
215  host_resolver()->AddRule("*", "127.0.0.1");
216  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
217
218  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
219  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
220
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);
228
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);
238
239  ASSERT_EQ(3, browser()->tab_strip_model()->count());
240
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));
248
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');"));
257
258  const std::string& kRetrieveLocalStorage =
259      WrapForJavascriptAndExtract(
260          "window.localStorage.getItem('testdata') || 'badval'");
261  std::string result;
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);
271
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"));
276
277  // Check that app1 tab cannot see the other cookies.
278  EXPECT_FALSE(HasCookie(tab0, "app2"));
279  EXPECT_FALSE(HasCookie(tab0, "normalPage"));
280
281  // Check that app2 tab cannot see the other cookies.
282  EXPECT_FALSE(HasCookie(tab1, "app1"));
283  EXPECT_FALSE(HasCookie(tab1, "normalPage"));
284
285  // Check that normal tab cannot see the other cookies.
286  EXPECT_FALSE(HasCookie(tab2, "app1"));
287  EXPECT_FALSE(HasCookie(tab2, "app2"));
288
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"));
294
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()->
302              GetController()));
303  chrome::Reload(browser(), CURRENT_TAB);
304  observer.Wait();
305  EXPECT_TRUE(HasCookie(tab0, "app1=3"));
306  EXPECT_FALSE(HasCookie(tab0, "app2"));
307  EXPECT_FALSE(HasCookie(tab0, "normalPage"));
308
309}
310
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.
313IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_NoCookieIsolationWithoutApp) {
314  host_resolver()->AddRule("*", "127.0.0.1");
315  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
316
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);
324
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);
334
335  ASSERT_EQ(3, browser()->tab_strip_model()->count());
336
337  // Check that tabs see each other's cookies.
338  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
339                        "app2=4"));
340  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
341                        "normalPage=5"));
342  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(0),
343                        "nonAppFrame=6"));
344  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
345                        "app1=3"));
346  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
347                        "normalPage=5"));
348  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(1),
349                        "nonAppFrame=6"));
350  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
351                        "app1=3"));
352  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
353                        "app2=4"));
354  EXPECT_TRUE(HasCookie(browser()->tab_strip_model()->GetWebContentsAt(2),
355                        "nonAppFrame=6"));
356
357  // Check that all tabs share the same localStorage if they have the same
358  // origin.
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');"));
368
369  const std::string& kRetrieveLocalStorage =
370      WrapForJavascriptAndExtract("window.localStorage.getItem('testdata')");
371  std::string result;
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);
381}
382
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
387#else
388#define MAYBE_SubresourceCookieIsolation SubresourceCookieIsolation
389#endif  // defined(OS_WIN) && !defined(NDEBUG)
390
391// Tests that subresource and media requests use the app's cookie store.
392// See http://crbug.com/141172.
393IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_SubresourceCookieIsolation) {
394  embedded_test_server()->RegisterRequestHandler(
395      base::Bind(&HandleExpectAndSetCookieRequest, embedded_test_server()));
396
397  host_resolver()->AddRule("*", "127.0.0.1");
398  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
399
400  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
401
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);
411
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));
423
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"));
429
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);
443  observer.Wait();
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"));
448
449  // Also create a non-app tab to ensure no new cookies were set in that jar.
450  ui_test_utils::NavigateToURLWithDisposition(
451      browser(), root_url,
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"));
458}
459
460// Test is flaky on Windows.
461// http://crbug.com/247667
462#if defined(OS_WIN)
463#define MAYBE_IsolatedAppProcessModel DISABLED_IsolatedAppProcessModel
464#else
465#define MAYBE_IsolatedAppProcessModel IsolatedAppProcessModel
466#endif  // defined(OS_WIN)
467
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.
471IN_PROC_BROWSER_TEST_F(IsolatedAppTest, MAYBE_IsolatedAppProcessModel) {
472  host_resolver()->AddRule("*", "127.0.0.1");
473  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
474
475  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
476
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);
484
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);
495
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);
501
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());
516
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),
520                     non_app_url);
521  EXPECT_NE(process_id_1,
522            browser()->tab_strip_model()->GetWebContentsAt(1)->
523                GetRenderProcessHost()->GetID());
524}
525
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
531IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_SessionStorage) {
532  host_resolver()->AddRule("*", "127.0.0.1");
533  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
534
535  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
536  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
537
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);
545
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');"));
554
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');"));
561
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');"));
568
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'");
574  std::string result;
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);
582
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);
590
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);
598}
599