#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "net/base/mock_host_resolver.h"
using content::ExecuteJavaScript;
using content::ExecuteJavaScriptAndExtractString;
using content::NavigationController;
using content::WebContents;
using content::RenderViewHost;
namespace {
std::wstring WrapForJavascriptAndExtract(
const wchar_t* javascript_expression) {
return std::wstring(L"window.domAutomationController.send(") +
javascript_expression + L")";
}
class IsolatedAppTest : public ExtensionBrowserTest {
public:
bool WARN_UNUSED_RESULT HasCookie(WebContents* contents, std::string cookie) {
int value_size;
std::string actual_cookie;
automation_util::GetCookies(contents->GetURL(), contents, &value_size,
&actual_cookie);
return actual_cookie.find(cookie) != std::string::npos;
}
const extensions::Extension* GetInstalledApp(WebContents* contents) {
const extensions::Extension* installed_app = NULL;
Profile* profile =
Profile::FromBrowserContext(contents->GetBrowserContext());
ExtensionService* service = profile->GetExtensionService();
if (service) {
installed_app = service->GetInstalledAppForRenderer(
contents->GetRenderProcessHost()->GetID());
}
return installed_app;
}
private:
virtual void SetUpCommandLine(CommandLine* command_line) {
ExtensionBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
}
};
}
IN_PROC_BROWSER_TEST_F(IsolatedAppTest, CookieIsolation) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
GURL::Replacements replace_host;
std::string host_str("localhost");
replace_host.SetHostStr(host_str);
base_url = base_url.ReplaceComponents(replace_host);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app2/main.html"),
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("non_app/main.html"),
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_EQ(3, browser()->tab_count());
WebContents* tab0 = chrome::GetWebContentsAt(browser(), 0);
WebContents* tab1 = chrome::GetWebContentsAt(browser(), 1);
WebContents* tab2 = chrome::GetWebContentsAt(browser(), 2);
ASSERT_TRUE(GetInstalledApp(tab0));
ASSERT_TRUE(GetInstalledApp(tab1));
ASSERT_TRUE(!GetInstalledApp(tab2));
RenderViewHost* app1_rvh = tab0->GetRenderViewHost();
RenderViewHost* app2_rvh = tab1->GetRenderViewHost();
RenderViewHost* non_app_rvh = tab2->GetRenderViewHost();
ASSERT_TRUE(ExecuteJavaScript(
app1_rvh, L"", L"window.localStorage.setItem('testdata', 'ls_app1');"));
ASSERT_TRUE(ExecuteJavaScript(
app2_rvh, L"", L"window.localStorage.setItem('testdata', 'ls_app2');"));
ASSERT_TRUE(ExecuteJavaScript(
non_app_rvh, L"",
L"window.localStorage.setItem('testdata', 'ls_normal');"));
const std::wstring& kRetrieveLocalStorage =
WrapForJavascriptAndExtract(
L"window.localStorage.getItem('testdata') || 'badval'");
std::string result;
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
app1_rvh, L"", kRetrieveLocalStorage.c_str(), &result));
EXPECT_EQ("ls_app1", result);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
app2_rvh, L"", kRetrieveLocalStorage.c_str(), &result));
EXPECT_EQ("ls_app2", result);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
non_app_rvh, L"", kRetrieveLocalStorage.c_str(), &result));
EXPECT_EQ("ls_normal", result);
EXPECT_TRUE(HasCookie(tab0, "app1=3"));
EXPECT_TRUE(HasCookie(tab1, "app2=4"));
EXPECT_TRUE(HasCookie(tab2, "normalPage=5"));
EXPECT_FALSE(HasCookie(tab0, "app2"));
EXPECT_FALSE(HasCookie(tab0, "normalPage"));
EXPECT_FALSE(HasCookie(tab1, "app1"));
EXPECT_FALSE(HasCookie(tab1, "normalPage"));
EXPECT_FALSE(HasCookie(tab2, "app1"));
EXPECT_FALSE(HasCookie(tab2, "app2"));
EXPECT_TRUE(HasCookie(tab0, "nonAppFrame=6"));
EXPECT_FALSE(HasCookie(tab2, "nonAppFrame"));
chrome::SelectNumberedTab(browser(), 0);
content::CrashTab(tab0);
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&chrome::GetActiveWebContents(browser())->GetController()));
chrome::Reload(browser(), CURRENT_TAB);
observer.Wait();
EXPECT_TRUE(HasCookie(tab0, "app1=3"));
EXPECT_FALSE(HasCookie(tab0, "app2"));
EXPECT_FALSE(HasCookie(tab0, "normalPage"));
}
IN_PROC_BROWSER_TEST_F(IsolatedAppTest, DISABLED_NoCookieIsolationWithoutApp) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
GURL::Replacements replace_host;
std::string host_str("localhost");
replace_host.SetHostStr(host_str);
base_url = base_url.ReplaceComponents(replace_host);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app2/main.html"),
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("non_app/main.html"),
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_EQ(3, browser()->tab_count());
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 0), "app2=4"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 0), "normalPage=5"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 0), "nonAppFrame=6"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 1), "app1=3"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 1), "normalPage=5"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 1), "nonAppFrame=6"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 2), "app1=3"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 2), "app2=4"));
EXPECT_TRUE(HasCookie(chrome::GetWebContentsAt(browser(), 2), "nonAppFrame=6"));
RenderViewHost* app1_rvh =
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost();
RenderViewHost* app2_rvh =
chrome::GetWebContentsAt(browser(), 1)->GetRenderViewHost();
RenderViewHost* non_app_rvh =
chrome::GetWebContentsAt(browser(), 2)->GetRenderViewHost();
ASSERT_TRUE(ExecuteJavaScript(
app1_rvh, L"", L"window.localStorage.setItem('testdata', 'ls_app1');"));
ASSERT_TRUE(ExecuteJavaScript(
app2_rvh, L"", L"window.localStorage.setItem('testdata', 'ls_app2');"));
ASSERT_TRUE(ExecuteJavaScript(
non_app_rvh, L"",
L"window.localStorage.setItem('testdata', 'ls_normal');"));
const std::wstring& kRetrieveLocalStorage =
WrapForJavascriptAndExtract(L"window.localStorage.getItem('testdata')");
std::string result;
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
app1_rvh, L"", kRetrieveLocalStorage.c_str(), &result));
EXPECT_EQ("ls_normal", result);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
app2_rvh, L"", kRetrieveLocalStorage.c_str(), &result));
EXPECT_EQ("ls_normal", result);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
non_app_rvh, L"", kRetrieveLocalStorage.c_str(), &result));
EXPECT_EQ("ls_normal", result);
}
IN_PROC_BROWSER_TEST_F(IsolatedAppTest, SubresourceCookieIsolation) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
GURL root_url = test_server()->GetURL("");
GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
GURL::Replacements replace_host;
std::string host_str("localhost");
replace_host.SetHostStr(host_str);
root_url = root_url.ReplaceComponents(replace_host);
base_url = base_url.ReplaceComponents(replace_host);
ui_test_utils::NavigateToURLWithDisposition(
browser(), root_url.Resolve("set-cookie?nonApp=1"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
WebContents* tab0 = chrome::GetWebContentsAt(browser(), 0);
ASSERT_FALSE(GetInstalledApp(tab0));
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
WebContents* tab1 = chrome::GetWebContentsAt(browser(), 1);
ASSERT_TRUE(GetInstalledApp(tab1));
EXPECT_TRUE(HasCookie(tab0, "nonApp=1"));
EXPECT_FALSE(HasCookie(tab0, "app1=3"));
EXPECT_FALSE(HasCookie(tab1, "nonApp=1"));
EXPECT_TRUE(HasCookie(tab1, "app1=3"));
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
content::Source<WebContents>(chrome::GetActiveWebContents(browser())));
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/app_subresources.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
observer.Wait();
EXPECT_FALSE(HasCookie(tab1, "nonAppMedia=1"));
EXPECT_TRUE(HasCookie(tab1, "app1Media=1"));
EXPECT_FALSE(HasCookie(tab1, "nonAppImage=1"));
EXPECT_TRUE(HasCookie(tab1, "app1Image=1"));
ui_test_utils::NavigateToURLWithDisposition(
browser(), root_url,
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
WebContents* tab2 = chrome::GetWebContentsAt(browser(), 2);
EXPECT_FALSE(HasCookie(tab2, "nonAppMedia=1"));
EXPECT_FALSE(HasCookie(tab2, "app1Media=1"));
EXPECT_FALSE(HasCookie(tab2, "nonAppImage=1"));
EXPECT_FALSE(HasCookie(tab2, "app1Image=1"));
}
IN_PROC_BROWSER_TEST_F(IsolatedAppTest, IsolatedAppProcessModel) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
GURL::Replacements replace_host;
std::string host_str("localhost");
replace_host.SetHostStr(host_str);
base_url = base_url.ReplaceComponents(replace_host);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
OpenWindow(chrome::GetWebContentsAt(browser(), 0),
base_url.Resolve("app1/main.html"), true, NULL);
OpenWindow(chrome::GetWebContentsAt(browser(), 0),
base_url.Resolve("non_app/main.html"), false, NULL);
ASSERT_EQ(4, browser()->tab_count());
int process_id_0 =
chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost()->GetID();
int process_id_1 =
chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID();
EXPECT_NE(process_id_0, process_id_1);
EXPECT_EQ(process_id_0,
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID());
EXPECT_NE(process_id_0,
chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost()->GetID());
const GURL& non_app_url(base_url.Resolve("non_app/main.html"));
NavigateInRenderer(chrome::GetWebContentsAt(browser(), 1), non_app_url);
EXPECT_NE(process_id_1,
chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID());
}
IN_PROC_BROWSER_TEST_F(IsolatedAppTest, SessionStorage) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app1")));
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("isolated_apps/app2")));
GURL base_url = test_server()->GetURL("files/extensions/isolated_apps/");
GURL::Replacements replace_host;
std::string host_str("localhost");
replace_host.SetHostStr(host_str);
base_url = base_url.ReplaceComponents(replace_host);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_TRUE(ExecuteJavaScript(
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost(),
L"",
L"window.sessionStorage.setItem('testdata', 'ss_app1');"));
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app2/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_TRUE(ExecuteJavaScript(
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost(),
L"",
L"window.sessionStorage.setItem('testdata', 'ss_app2');"));
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("non_app/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_TRUE(ExecuteJavaScript(
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost(),
L"",
L"window.sessionStorage.setItem('testdata', 'ss_normal');"));
const std::wstring& kRetrieveSessionStorage =
WrapForJavascriptAndExtract(
L"window.sessionStorage.getItem('testdata') || 'badval'");
std::string result;
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app1/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost(),
L"", kRetrieveSessionStorage.c_str(), &result));
EXPECT_EQ("ss_app1", result);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("app2/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost(),
L"", kRetrieveSessionStorage.c_str(), &result));
EXPECT_EQ("ss_app2", result);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("non_app/main.html"),
CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
chrome::GetWebContentsAt(browser(), 0)->GetRenderViewHost(),
L"", kRetrieveSessionStorage.c_str(), &result));
EXPECT_EQ("ss_normal", result);
}