| Index: chrome/browser/extensions/api/web_request/web_request_apitest.cc
 | 
| diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
 | 
| index 689edf0961772cf262738164502912176a36e5bb..8f1aa9c4cd46c3a5d22cf55f133111005d101bd3 100644
 | 
| --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
 | 
| +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
 | 
| @@ -15,6 +15,7 @@
 | 
|  #include "chrome/browser/extensions/extension_action_runner.h"
 | 
|  #include "chrome/browser/extensions/extension_apitest.h"
 | 
|  #include "chrome/browser/extensions/extension_service.h"
 | 
| +#include "chrome/browser/extensions/extension_with_management_policy_apitest.h"
 | 
|  #include "chrome/browser/extensions/tab_helper.h"
 | 
|  #include "chrome/browser/extensions/test_extension_dir.h"
 | 
|  #include "chrome/browser/profiles/profile.h"
 | 
| @@ -46,6 +47,7 @@
 | 
|  #include "extensions/test/result_catcher.h"
 | 
|  #include "net/dns/mock_host_resolver.h"
 | 
|  #include "net/test/embedded_test_server/embedded_test_server.h"
 | 
| +#include "net/test/embedded_test_server/http_request.h"
 | 
|  #include "net/test/test_data_directory.h"
 | 
|  #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 | 
|  #include "net/url_request/test_url_fetcher_factory.h"
 | 
| @@ -85,7 +87,7 @@ class CancelLoginDialog : public content::NotificationObserver {
 | 
|   private:
 | 
|    content::NotificationRegistrar registrar_;
 | 
|  
 | 
| - DISALLOW_COPY_AND_ASSIGN(CancelLoginDialog);
 | 
| +  DISALLOW_COPY_AND_ASSIGN(CancelLoginDialog);
 | 
|  };
 | 
|  
 | 
|  // Sends an XHR request to the provided host, port, and path, and responds when
 | 
| @@ -115,11 +117,11 @@ void PerformXhrInFrame(content::RenderFrameHost* frame,
 | 
|    EXPECT_TRUE(success);
 | 
|  }
 | 
|  
 | 
| -// Returns the current count of webRequests received by the |extension| in
 | 
| -// the background page (assumes the extension stores a value on the window
 | 
| -// object). Returns -1 if something goes awry.
 | 
| -int GetWebRequestCountFromBackgroundPage(const Extension* extension,
 | 
| -                                         content::BrowserContext* context) {
 | 
| +// Returns the current count of a variable stored in the |extension| background
 | 
| +// page. Returns -1 if something goes awry.
 | 
| +int GetCountFromBackgroundPage(const Extension* extension,
 | 
| +                               content::BrowserContext* context,
 | 
| +                               const std::string& variable_name) {
 | 
|    ExtensionHost* host =
 | 
|        ProcessManager::Get(context)->GetBackgroundHostForExtension(
 | 
|            extension->id());
 | 
| @@ -129,12 +131,20 @@ int GetWebRequestCountFromBackgroundPage(const Extension* extension,
 | 
|    int count = -1;
 | 
|    if (!ExecuteScriptAndExtractInt(
 | 
|            host->host_contents(),
 | 
| -          "window.domAutomationController.send(window.webRequestCount)",
 | 
| -          &count))
 | 
| +          "window.domAutomationController.send(" + variable_name + ")", &count))
 | 
|      return -1;
 | 
|    return count;
 | 
|  }
 | 
|  
 | 
| +// Returns the current count of webRequests received by the |extension| in
 | 
| +// the background page (assumes the extension stores a value on the window
 | 
| +// object). Returns -1 if something goes awry.
 | 
| +int GetWebRequestCountFromBackgroundPage(const Extension* extension,
 | 
| +                                         content::BrowserContext* context) {
 | 
| +  return GetCountFromBackgroundPage(extension, context,
 | 
| +                                    "window.webRequestCount");
 | 
| +}
 | 
| +
 | 
|  // A test delegate to wait allow waiting for responses to complete with an
 | 
|  // expected status and given content.
 | 
|  // TODO(devlin): Other similar classes exist elsewhere. Pull this into a common
 | 
| @@ -954,4 +964,204 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +// Tests that the webRequest events aren't dispatched when the request initiator
 | 
| +// is protected by policy.
 | 
| +IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
 | 
| +                       InitiatorProtectedByPolicy) {
 | 
| +  // We expect that no request will be hidden or modification blocked. This
 | 
| +  // means that the request to example.com will be seen by the extension.
 | 
| +  {
 | 
| +    ExtensionManagementPolicyUpdater pref(&policy_provider_);
 | 
| +    pref.AddRuntimeBlockedHost("*", "*://notexample.com");
 | 
| +  }
 | 
| +
 | 
| +  ASSERT_TRUE(StartEmbeddedTestServer());
 | 
| +
 | 
| +  // Host navigated to.
 | 
| +  const std::string example_com = "example.com";
 | 
| +
 | 
| +  // URL of a page that initiates a cross domain requests when navigated to.
 | 
| +  const GURL extension_test_url = embedded_test_server()->GetURL(
 | 
| +      example_com,
 | 
| +      "/extensions/api_test/webrequest/policy_blocked/ref_remote_js.html");
 | 
| +
 | 
| +  ExtensionTestMessageListener listener("ready", false);
 | 
| +  const Extension* extension =
 | 
| +      LoadExtension(test_data_dir_.AppendASCII("webrequest/policy_blocked"));
 | 
| +  ASSERT_TRUE(extension) << message_;
 | 
| +  EXPECT_TRUE(listener.WaitUntilSatisfied());
 | 
| +
 | 
| +  // Extension communicates back using this listener name.
 | 
| +  const std::string listener_message = "protected_origin";
 | 
| +
 | 
| +  // The number of requests initiated by a protected origin is tracked in
 | 
| +  // the extension's background page under this variable name.
 | 
| +  const std::string request_counter_name = "window.protectedOriginCount";
 | 
| +
 | 
| +  EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
 | 
| +                                          request_counter_name));
 | 
| +
 | 
| +  // Wait until all remote Javascript files have been blocked / pulled down.
 | 
| +  ui_test_utils::NavigateToURLWithDisposition(
 | 
| +      browser(), extension_test_url, WindowOpenDisposition::CURRENT_TAB,
 | 
| +      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 | 
| +
 | 
| +  // Domain that hosts javascript file referenced by example_com.
 | 
| +  const std::string example2_com = "example2.com";
 | 
| +
 | 
| +  // The server saw a request for the remote Javascript file.
 | 
| +  EXPECT_TRUE(BrowsedTo(example2_com));
 | 
| +
 | 
| +  // The request was seen by the extension.
 | 
| +  EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
 | 
| +                                          request_counter_name));
 | 
| +
 | 
| +  // Clear the list of domains the server has seen.
 | 
| +  ClearRequestLog();
 | 
| +
 | 
| +  // Make sure we've cleared the embedded server history.
 | 
| +  EXPECT_FALSE(BrowsedTo(example2_com));
 | 
| +
 | 
| +  // Set the policy to hide requests to example.com or any resource
 | 
| +  // it includes. We expect that in this test, the request to example2.com
 | 
| +  // will not be seen by the extension.
 | 
| +  {
 | 
| +    ExtensionManagementPolicyUpdater pref(&policy_provider_);
 | 
| +    pref.AddRuntimeBlockedHost("*", "*://" + example_com);
 | 
| +  }
 | 
| +
 | 
| +  // Wait until all remote Javascript files have been pulled down.
 | 
| +  ui_test_utils::NavigateToURLWithDisposition(
 | 
| +      browser(), extension_test_url, WindowOpenDisposition::CURRENT_TAB,
 | 
| +      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 | 
| +
 | 
| +  // The server saw a request for the remote Javascript file.
 | 
| +  EXPECT_TRUE(BrowsedTo(example2_com));
 | 
| +
 | 
| +  // The request was hidden from the extension.
 | 
| +  EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
 | 
| +                                          request_counter_name));
 | 
| +}
 | 
| +
 | 
| +// Tests that the webRequest events aren't dispatched when the URL of the
 | 
| +// request is protected by policy.
 | 
| +IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
 | 
| +                       UrlProtectedByPolicy) {
 | 
| +  // Host protected by policy.
 | 
| +  const std::string protected_domain = "example.com";
 | 
| +
 | 
| +  {
 | 
| +    ExtensionManagementPolicyUpdater pref(&policy_provider_);
 | 
| +    pref.AddRuntimeBlockedHost("*", "*://" + protected_domain);
 | 
| +  }
 | 
| +
 | 
| +  ASSERT_TRUE(StartEmbeddedTestServer());
 | 
| +
 | 
| +  LoadExtension(test_data_dir_.AppendASCII("webrequest/policy_blocked"));
 | 
| +
 | 
| +  // Listen in case extension sees the requst.
 | 
| +  ExtensionTestMessageListener before_request_listener("protected_url", false);
 | 
| +
 | 
| +  // Path to resolve during test navigations.
 | 
| +  const std::string test_path = "/defaultresponse?protected_url";
 | 
| +
 | 
| +  // Navigate to the protected domain and wait until page fully loads.
 | 
| +  ui_test_utils::NavigateToURLWithDisposition(
 | 
| +      browser(), embedded_test_server()->GetURL(protected_domain, test_path),
 | 
| +      WindowOpenDisposition::CURRENT_TAB,
 | 
| +      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 | 
| +
 | 
| +  // The server saw a request for the protected site.
 | 
| +  EXPECT_TRUE(BrowsedTo(protected_domain));
 | 
| +
 | 
| +  // The request was hidden from the extension.
 | 
| +  EXPECT_FALSE(before_request_listener.was_satisfied());
 | 
| +
 | 
| +  // Host not protected by policy.
 | 
| +  const std::string unprotected_domain = "notblockedexample.com";
 | 
| +
 | 
| +  // Now we'll test browsing to a non-protected website where we expect the
 | 
| +  // extension to see the request.
 | 
| +  ui_test_utils::NavigateToURLWithDisposition(
 | 
| +      browser(), embedded_test_server()->GetURL(unprotected_domain, test_path),
 | 
| +      WindowOpenDisposition::CURRENT_TAB,
 | 
| +      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 | 
| +
 | 
| +  // The server saw a request for the non-protected site.
 | 
| +  EXPECT_TRUE(BrowsedTo(unprotected_domain));
 | 
| +
 | 
| +  // The request was visible from the extension.
 | 
| +  EXPECT_TRUE(before_request_listener.was_satisfied());
 | 
| +}
 | 
| +
 | 
| +// Test that no webRequest events are seen for a protected host during normal
 | 
| +// navigation. This replicates most of the tests from
 | 
| +// WebRequestWithWithheldPermissions with a protected host. Granting a tab
 | 
| +// specific permission shouldn't bypass our policy.
 | 
| +IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
 | 
| +                       WebRequestProtectedByPolicy) {
 | 
| +  FeatureSwitch::ScopedOverride enable_scripts_require_action(
 | 
| +      FeatureSwitch::scripts_require_action(), true);
 | 
| +
 | 
| +  // Host protected by policy.
 | 
| +  const std::string protected_domain = "example.com";
 | 
| +
 | 
| +  {
 | 
| +    ExtensionManagementPolicyUpdater pref(&policy_provider_);
 | 
| +    pref.AddRuntimeBlockedHost("*", "*://" + protected_domain);
 | 
| +  }
 | 
| +
 | 
| +  ASSERT_TRUE(StartEmbeddedTestServer());
 | 
| +
 | 
| +  ExtensionTestMessageListener listener("ready", false);
 | 
| +  const Extension* extension =
 | 
| +      LoadExtension(test_data_dir_.AppendASCII("webrequest_activetab"));
 | 
| +  ASSERT_TRUE(extension) << message_;
 | 
| +  EXPECT_TRUE(listener.WaitUntilSatisfied());
 | 
| +
 | 
| +  // Navigate the browser to a page in a new tab.
 | 
| +  GURL url = embedded_test_server()->GetURL(protected_domain, "/empty.html");
 | 
| +  chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK);
 | 
| +  params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
 | 
| +  ui_test_utils::NavigateToURL(¶ms);
 | 
| +
 | 
| +  content::WebContents* web_contents =
 | 
| +      browser()->tab_strip_model()->GetActiveWebContents();
 | 
| +  ASSERT_TRUE(web_contents);
 | 
| +  ExtensionActionRunner* runner =
 | 
| +      ExtensionActionRunner::GetForWebContents(web_contents);
 | 
| +  ASSERT_TRUE(runner);
 | 
| +
 | 
| +  int port = embedded_test_server()->port();
 | 
| +  const std::string kXhrPath = "simple.html";
 | 
| +
 | 
| +  // The extension shouldn't have currently received any webRequest events,
 | 
| +  // since it doesn't have permission (and shouldn't receive any from an XHR).
 | 
| +  EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile()));
 | 
| +  PerformXhrInFrame(web_contents->GetMainFrame(), protected_domain, port,
 | 
| +                    kXhrPath);
 | 
| +  EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile()));
 | 
| +
 | 
| +  // Grant activeTab permission, and perform another XHR. The extension should
 | 
| +  // still be blocked due to ExtensionSettings policy on example.com.
 | 
| +  // Only records ACCESS_WITHHELD, not ACCESS_DENIED, this is why it matches
 | 
| +  // BLOCKED_ACTION_NONE.
 | 
| +  EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension));
 | 
| +  runner->set_default_bubble_close_action_for_testing(
 | 
| +      base::WrapUnique(new ToolbarActionsBarBubbleDelegate::CloseAction(
 | 
| +          ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE)));
 | 
| +  runner->RunAction(extension, true);
 | 
| +  base::RunLoop().RunUntilIdle();
 | 
| +  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
 | 
| +  EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension));
 | 
| +  int xhr_count = GetWebRequestCountFromBackgroundPage(extension, profile());
 | 
| +  // ... which means that we should have a non-zero xhr count if the policy
 | 
| +  // didn't block the events.
 | 
| +  EXPECT_EQ(0, xhr_count);
 | 
| +  // And the extension should also block future events.
 | 
| +  PerformXhrInFrame(web_contents->GetMainFrame(), protected_domain, port,
 | 
| +                    kXhrPath);
 | 
| +  EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile()));
 | 
| +}
 | 
| +
 | 
|  }  // namespace extensions
 | 
| 
 |