Index: chrome/browser/extensions/process_manager_browsertest.cc |
diff --git a/chrome/browser/extensions/process_manager_browsertest.cc b/chrome/browser/extensions/process_manager_browsertest.cc |
index 980318c77b803ca623a644153d87d3799c12e521..eacd78fdf043b685f5dac17c7ea25c5fe092a9a7 100644 |
--- a/chrome/browser/extensions/process_manager_browsertest.cc |
+++ b/chrome/browser/extensions/process_manager_browsertest.cc |
@@ -4,23 +4,111 @@ |
#include "extensions/browser/process_manager.h" |
+#include "base/path_service.h" |
+#include "base/strings/stringprintf.h" |
#include "chrome/browser/extensions/browser_action_test_util.h" |
#include "chrome/browser/extensions/extension_browsertest.h" |
#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/test_extension_dir.h" |
#include "chrome/browser/ui/tabs/tab_strip_model.h" |
+#include "chrome/common/extensions/extension_process_policy.h" |
#include "chrome/test/base/in_process_browser_test.h" |
#include "chrome/test/base/ui_test_utils.h" |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/web_contents.h" |
+#include "content/public/test/browser_test_utils.h" |
#include "content/public/test/test_utils.h" |
+#include "extensions/common/value_builder.h" |
#include "net/dns/mock_host_resolver.h" |
#include "net/test/embedded_test_server/embedded_test_server.h" |
+using content::WebContents; |
+ |
namespace extensions { |
// Exists as a browser test because ExtensionHosts are hard to create without |
// a real browser. |
-typedef ExtensionBrowserTest ProcessManagerBrowserTest; |
+class ProcessManagerBrowserTest : public ExtensionBrowserTest { |
+ public: |
+ void SetUpOnMainThread() override { |
+ host_resolver()->AddRule("*", "127.0.0.1"); |
+ |
+ // Add content/test/data so we can use cross_site_iframe_factory.html |
+ base::FilePath test_data_dir; |
+ ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); |
+ embedded_test_server()->ServeFilesFromDirectory( |
+ test_data_dir.AppendASCII("content/test/data/")); |
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
+ } |
+ |
+ // Create and install an extension that has a couple of web-accessible |
+ // resources and, optionally, a background process. |
+ const Extension* CreateExtension(const std::string& name, |
+ bool has_background_process) { |
+ scoped_ptr<TestExtensionDir> dir(new TestExtensionDir); |
+ |
+ DictionaryBuilder manifest; |
+ manifest.Set("name", name) |
+ .Set("version", "1.0") |
+ .Set("manifest_version", 2) |
+ .Set("web_accessible_resources", ListBuilder() |
+ .Append("blank_iframe.html") |
+ .Append("http_iframe.html") |
+ .Append("two_http_iframes.html")); |
+ |
+ if (has_background_process) { |
+ manifest.Set("background", |
+ DictionaryBuilder().Set("scripts", |
+ ListBuilder().Append("script.js"))); |
+ dir->WriteFile(FILE_PATH_LITERAL("script.js"), |
+ "console.log('" + name + " running');"); |
+ } |
+ |
+ dir->WriteFile(FILE_PATH_LITERAL("blank_iframe.html"), |
+ base::StringPrintf("<html><body>%s, blank iframe:" |
+ " <iframe width=80 height=80></iframe>" |
+ "</body></html>", |
+ name.c_str())); |
+ std::string iframe_url = |
+ embedded_test_server() |
+ ->GetURL("w.com", "/cross_site_iframe_factory.html?w") |
+ .spec(); |
+ std::string iframe_url2 = |
+ embedded_test_server() |
+ ->GetURL("x.com", "/cross_site_iframe_factory.html?x") |
+ .spec(); |
+ dir->WriteFile( |
+ FILE_PATH_LITERAL("http_iframe.html"), |
+ base::StringPrintf("<html><body>%s, http:// iframe:" |
+ " <iframe width=80 height=80 src='%s'></iframe>" |
+ "</body></html>", |
+ name.c_str(), iframe_url.c_str())); |
+ dir->WriteFile(FILE_PATH_LITERAL("two_http_iframes.html"), |
+ base::StringPrintf( |
+ "<html><body>%s, two http:// iframes:" |
+ " <iframe width=80 height=80 src='%s'></iframe>" |
+ " <iframe width=80 height=80 src='%s'></iframe>" |
+ "</body></html>", |
+ name.c_str(), iframe_url.c_str(), iframe_url2.c_str())); |
+ dir->WriteManifest(manifest.ToJSON()); |
+ |
+ const Extension* extension = LoadExtension(dir->unpacked_path()); |
+ EXPECT_TRUE(extension); |
+ temp_dirs_.push_back(dir.release()); |
+ return extension; |
+ } |
+ |
+ int IfExtensionsIsolated(int value) { |
+ if (content::AreAllSitesIsolatedForTesting() || |
+ IsIsolateExtensionsEnabled()) { |
+ return value; |
+ } |
+ return 0; |
+ } |
+ |
+ private: |
+ ScopedVector<TestExtensionDir> temp_dirs_; |
+}; |
// Test that basic extension loading creates the appropriate ExtensionHosts |
// and background pages. |
@@ -193,4 +281,111 @@ IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, KeepaliveOnNetworkRequest) { |
EXPECT_EQ(baseline_keepalive, pm->GetLazyKeepaliveCount(extension.get())); |
} |
+// Tests which RenderFrameHosts are tracked by ProcessManager, including: |
+// http iframes inside of extension pages, extension iframes inside of extension |
+// pages, and about:blank iframes inside of extension content. |
+IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest, FrameClassification) { |
+ // The expections here assume that we wish to have the ProcessManager |
+ // distinguish between extension vs. non-extension frames in extension |
+ // processes. This test exercises about:blank cases that will be hard for |
+ // the ProcessManager to get right, until |
+ // https://code.google.com/p/chromium/issues/detail?id=498580 is fixed, and |
+ // the ProcessManager is made to query the effective origin. |
+ ProcessManager* pm = ProcessManager::Get(profile()); |
+ |
+ size_t expected_extension_frames = 0; |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Install one script-injecting extension with background page, and an |
+ // extension with web accessible resources. |
+ const Extension* extension1 = CreateExtension("Extension One", true); |
+ |
+ expected_extension_frames += 1; // extension 1 background page |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ const Extension* extension2 = CreateExtension("Extension Two", false); |
+ expected_extension_frames += 0; // extension 2 / no background page |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Open two a.com tabs (with cross site http iframes). IsolateExtensions mode |
+ // should have no effect so far, since there are no frames straddling the |
+ // extension/web boundary. |
+ GURL tab1_url = embedded_test_server()->GetURL( |
+ "a.com", "/cross_site_iframe_factory.html?a(b,c)"); |
+ ui_test_utils::NavigateToURL(browser(), tab1_url); |
+ |
+ expected_extension_frames += 0; // only http frames added to tab1 |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ WebContents* tab1 = browser()->tab_strip_model()->GetWebContentsAt(0); |
+ GURL tab2_url = embedded_test_server()->GetURL( |
+ "a.com", "/cross_site_iframe_factory.html?a(d,e)"); |
+ AddTabAtIndex(1, tab2_url, ui::PAGE_TRANSITION_TYPED); |
+ WebContents* tab2 = browser()->tab_strip_model()->GetWebContentsAt(1); |
+ |
+ expected_extension_frames += 0; // only http frames added to tab2 |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Tab1 navigates its first iframe to a resource of extension1. |
+ content::NavigateIframeToURL( |
+ tab1, "child-0", extension1->GetResourceURL("/blank_iframe.html")); |
+ |
+ expected_extension_frames += IfExtensionsIsolated(2); // A frame and its blank child. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Tab2 navigates its first iframe to a resource of extension1. |
+ content::NavigateIframeToURL( |
+ tab2, "child-0", extension1->GetResourceURL("/blank_iframe.html")); |
+ |
+ expected_extension_frames += IfExtensionsIsolated(2); // A frame and its blank child. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Tab1 navigates its second iframe to a resource of extension2. |
+ content::NavigateIframeToURL( |
+ tab1, "child-1", extension2->GetResourceURL("/blank_iframe.html")); |
+ |
+ expected_extension_frames += IfExtensionsIsolated(2); // A frame and its blank child. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Tab2 navigates its second iframe to a resource of extension2. |
+ content::NavigateIframeToURL( |
+ tab2, "child-1", extension2->GetResourceURL("/blank_iframe.html")); |
+ |
+ expected_extension_frames += IfExtensionsIsolated(2); // A frame and its blank child. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Install extension3 (identical config to extension2) |
+ const Extension* extension3 = CreateExtension("Extension Three", false); |
+ |
+ expected_extension_frames += 0; // No background page. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Navigate Tab2 to a top-level page from extension3. |
+ ui_test_utils::NavigateToURL(browser(), |
+ extension3->GetResourceURL("blank_iframe.html")); |
+ |
+ expected_extension_frames -= IfExtensionsIsolated(4); // Old children. |
+ expected_extension_frames += 2; // New page and its child, always in extension process. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ // Navigate tab2 to a different extension3 page containing a web iframe. |
+ ui_test_utils::NavigateToURL(browser(), |
+ extension3->GetResourceURL("http_iframe.html")); |
+ |
+ expected_extension_frames -= 1; // http iframe is not an extension frame. |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ browser()->tab_strip_model()->ActivateTabAt(0, true); |
+ ui_test_utils::NavigateToURL(browser(), |
+ GURL("about:blank")); |
+ |
+ expected_extension_frames -= IfExtensionsIsolated(4); |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ extension2->GetResourceURL("/two_http_iframes.html")); |
+ expected_extension_frames += 1; |
+ EXPECT_EQ(expected_extension_frames, pm->GetAllFrames().size()); |
+} |
+ |
} // namespace extensions |