Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / isolated_app_browsertest.cc
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
37 std::string WrapForJavascriptAndExtract(const char* javascript_expression) {
38   return std::string("window.domAutomationController.send(") +
39       javascript_expression + ")";
40 }
41
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.
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
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:
128   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
129     ExtensionBrowserTest::SetUpCommandLine(command_line);
130     command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
131   }
132 };
133
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
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.
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.
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.
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
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