Commit dad325b1 authored by Kelvin Jiang's avatar Kelvin Jiang Committed by Commit Bot

[DNR] Implement GetMatchedRules API call (initial functionality)

This CL adds the following functionality:
 - GetMatchedRules API call, to get all rules an extension has matched
 - Ability for extension to specify a tab ID to filter rules in
   GetMatchedRules

Bug: 983761
Change-Id: I3672d84cc23be0e21a1387ede52923c3fe6354ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1913611Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Commit-Queue: Kelvin Jiang <kelvinjiang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#728248}
parent 17bbec68
......@@ -70,4 +70,8 @@ IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestAPItest,
ASSERT_TRUE(RunExtensionTest("on_rules_matched_debug")) << message_;
}
IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestAPItest, GetMatchedRules) {
ASSERT_TRUE(RunExtensionTest("get_matched_rules")) << message_;
}
} // namespace
......@@ -541,7 +541,7 @@ void ExtensionActionRunner::DidFinishNavigation(
int tab_id = ExtensionTabUtil::GetTabId(web_contents());
declarative_net_request::ActionTracker& action_tracker =
rules_monitor_service->action_tracker();
action_tracker.ResetActionCountForTab(tab_id,
action_tracker.ResetTrackedInfoForTab(tab_id,
navigation_handle->GetNavigationId());
}
}
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Navigates to |url| and invokes |callback| when the navigation is complete.
function navigateTab(url, callback) {
chrome.tabs.onUpdated.addListener(function updateCallback(_, info, tab) {
if (info.status == 'complete' && tab.url == url) {
chrome.tabs.onUpdated.removeListener(updateCallback);
callback(tab);
}
});
chrome.tabs.update({url: url});
}
var testServerPort;
function getServerURL(host) {
if (!testServerPort)
throw new Error('Called getServerURL outside of runTests.');
return `http://${host}:${testServerPort}/`;
}
var tests = [function testGetMatchedRules() {
const url = getServerURL('abc.com');
navigateTab(url, (tab) => {
chrome.declarativeNetRequest.getMatchedRules((details) => {
chrome.test.assertTrue(!!details.rulesMatchedInfo);
const matchedRules = details.rulesMatchedInfo;
chrome.test.assertEq(1, matchedRules.length);
const matchedRule = matchedRules[0];
// The matched rule's timestamp's cannot be verified, but it should be
// populated.
chrome.test.assertTrue(matchedRule.hasOwnProperty('timeStamp'));
delete matchedRule.timeStamp;
const expectedRuleInfo = {
rule: {ruleId: 1, sourceType: 'manifest'},
tabId: tab.id
};
// Sanity check that the RulesMatchedInfo fields are populated
// correctly.
chrome.test.assertTrue(
chrome.test.checkDeepEq(expectedRuleInfo, matchedRule));
chrome.test.succeed();
});
});
}];
chrome.test.getConfig(function(config) {
testServerPort = config.testServer.port;
chrome.test.runTests(tests);
});
{
"name": "Test extension",
"declarative_net_request": {
"rule_resources": [
"rules.json"
]
},
"manifest_version": 2,
"permissions": [
"declarativeNetRequest",
"declarativeNetRequestFeedback",
"tabs"
],
"version": "1.0",
"background": {
"scripts": [
"background.js"
]
}
}
[{
"id" : 1,
"action": { "type" : "block" },
"condition" : {"urlFilter" : "abc*", "resourceTypes" : ["main_frame"] }
}]
......@@ -5,6 +5,7 @@
#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
#include <list>
#include <map>
#include <vector>
......@@ -39,11 +40,11 @@ class ActionTracker {
// called by an extension.
void OnPreferenceEnabled(const ExtensionId& extension_id) const;
// Clears the action count for the specified |extension_id| for all tabs.
// Clears the TrackedInfo for the specified |extension_id| for all tabs.
// Called when an extension's ruleset is removed.
void ClearExtensionData(const ExtensionId& extension_id);
// Clears the action count for every extension for the specified |tab_id|.
// Clears the TrackedInfo for every extension for the specified |tab_id|.
// Called when the tab has been closed.
void ClearTabData(int tab_id);
......@@ -52,8 +53,14 @@ class ActionTracker {
void ClearPendingNavigation(int64_t navigation_id);
// Called when a main-frame navigation to a different document commits.
// Updates the badge count for all extensions for the given |tab_id|.
void ResetActionCountForTab(int tab_id, int64_t navigation_id);
// Updates the TrackedInfo for all extensions for the given |tab_id|.
void ResetTrackedInfoForTab(int tab_id, int64_t navigation_id);
// Returns all matched rules for |extension_id|. If |tab_id| is provided, only
// rules matched for |tab_id| will be returned.
std::vector<api::declarative_net_request::MatchedRuleInfo> GetMatchedRules(
const ExtensionId& extension_id,
base::Optional<int> tab_id) const;
private:
// Template key type used for TrackedInfo, specified by an extension_id and
......@@ -76,9 +83,33 @@ class ActionTracker {
using ExtensionTabIdKey = TrackedInfoContextKey<int>;
using ExtensionNavigationIdKey = TrackedInfoContextKey<int64_t>;
// Represents a matched rule. This is used as a lightweight version of
// api::declarative_net_request::MatchedRuleInfo.
struct TrackedRule {
TrackedRule(int rule_id,
api::declarative_net_request::SourceType source_type);
TrackedRule(const TrackedRule& other) = delete;
TrackedRule& operator=(const TrackedRule& other) = delete;
const int rule_id;
const api::declarative_net_request::SourceType source_type;
};
// Info tracked for each ExtensionTabIdKey or ExtensionNavigationIdKey.
struct TrackedInfo {
TrackedInfo();
~TrackedInfo();
TrackedInfo(const TrackedInfo& other) = delete;
TrackedInfo& operator=(const TrackedInfo& other) = delete;
TrackedInfo(TrackedInfo&&);
TrackedInfo& operator=(TrackedInfo&&);
// The number of actions matched. Invalid when the corresponding
// TrackedInfoContextKey has a tab_id of -1. Does not include allow rules.
size_t action_count = 0;
// The list of rules matched. Includes allow rules.
std::list<TrackedRule> matched_rules;
};
// Called from OnRuleMatched. Dispatches a OnRuleMatchedDebug event to the
......@@ -87,14 +118,23 @@ class ActionTracker {
const RequestAction& request_action,
api::declarative_net_request::RequestDetails request_details);
// Maps a pair of (extension ID, tab ID) to the number of actions matched for
// the extension and tab specified.
std::map<ExtensionTabIdKey, TrackedInfo> actions_matched_;
// For all matched rules attributed to |tab_id|, set their tab ID to the
// unknown tab ID (-1). Called by ClearTabData and ResetActionCountForTab.
void TransferRulesOnTabInvalid(int tab_id);
// Converts an internally represented |tracked_rule| to a MatchedRuleInfo.
api::declarative_net_request::MatchedRuleInfo CreateMatchedRuleInfo(
const TrackedRule& tracked_rule,
int tab_id) const;
// Maps a pair of (extension ID, tab ID) to the TrackedInfo for that pair.
// TODO(crbug.com/1035106): Prune the rules for the invalid tab ID to prevent
// this from growing unbounded.
std::map<ExtensionTabIdKey, TrackedInfo> rules_tracked_;
// Maps a pair of (extension ID, navigation ID) to the number of actions
// matched for the main-frame request associated with the navigation ID in the
// key. These actions are added to |actions_matched_| once the navigation
// commits.
// Maps a pair of (extension ID, navigation ID) to the TrackedInfo matched for
// the main-frame request associated with the navigation ID in the key. The
// TrackedInfo is added to |rules_tracked_| once the navigation commits.
std::map<ExtensionNavigationIdKey, TrackedInfo> pending_navigation_actions_;
content::BrowserContext* browser_context_;
......
......@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
#include "base/optional.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
......@@ -273,7 +274,32 @@ DeclarativeNetRequestGetMatchedRulesFunction::
ExtensionFunction::ResponseAction
DeclarativeNetRequestGetMatchedRulesFunction::Run() {
return RespondNow(NoArguments());
using Params = dnr_api::GetMatchedRules::Params;
base::string16 error;
std::unique_ptr<Params> params(Params::Create(*args_, &error));
EXTENSION_FUNCTION_VALIDATE(params);
EXTENSION_FUNCTION_VALIDATE(error.empty());
base::Optional<int> tab_id;
// TODO(crbug.com/983761): Add timestamp filtering as well.
if (params->filter && params->filter->tab_id)
tab_id = *params->filter->tab_id;
declarative_net_request::RulesMonitorService* rules_monitor_service =
declarative_net_request::RulesMonitorService::Get(browser_context());
DCHECK(rules_monitor_service);
const declarative_net_request::ActionTracker& action_tracker =
rules_monitor_service->action_tracker();
dnr_api::RulesMatchedDetails details;
details.rules_matched_info =
action_tracker.GetMatchedRules(extension_id(), tab_id);
return RespondNow(
ArgumentList(dnr_api::GetMatchedRules::Results::Create(details)));
}
DeclarativeNetRequestSetActionCountAsBadgeTextFunction::
......
......@@ -151,7 +151,7 @@
"contexts": ["blessed_extension"]
},
"declarativeNetRequest.getMatchedRules": {
"dependencies": ["permission:declarativeNetRequest"],
"dependencies": ["permission:declarativeNetRequest", "permission:declarativeNetRequestFeedback"],
"contexts": ["blessed_extension"],
"channel": "trunk"
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment