0

[DNR] Improve request method rule conditions for non-HTTP(s) requests

We previously added HTTP request method based matching for
declarativeNetRequest rules, but non-HTTP(s) requests were treated as
having the GET request method. With this change, we instead consider
non-HTTP(s) requests to have a special NON_HTTP request method. The
result is that rules with a requestMethods condition will no longer
match non-HTTP(s) requests. Rules with an excludedRequestMethods
condition will continue to match non-HTTP(s) requests, even if every
HTTP request method is excluded.

Bug: 1013583
Change-Id: Ib140894cba86e7fd59861fe2594c2b449ae4fdeb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2940865
Commit-Queue: Charlie Harrison <csharrison@chromium.org>
Reviewed-by: Charlie Harrison <csharrison@chromium.org>
Reviewed-by: Karan Bhatia <karandeepb@chromium.org>
Reviewed-by: Kelvin Jiang <kelvinjiang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#893014}
This commit is contained in:
Dave Vandyke
2021-06-16 15:09:22 +00:00
committed by Chromium LUCI CQ
parent 28cf8364ac
commit 2d9121fa22
8 changed files with 105 additions and 11 deletions
chrome/browser/extensions/api/declarative_net_request
components
subresource_filter
url_pattern_index
extensions

@@ -5924,6 +5924,92 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
} }
} }
// Tests that the "requestMethods" and "excludedRequestMethods" properties of a
// rule condition are considered properly for non-HTTP(s) requests.
IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
BlockRequests_NonHTTPMethods) {
// Load an extension with some DNR rules that have different request method
// conditions.
std::vector<TestRule> rules;
TestRule rule1 = CreateGenericRule(1);
rule1.condition->url_filter = "default";
rules.push_back(rule1);
TestRule rule2 = CreateGenericRule(2);
rule2.condition->url_filter = "all_methods";
rule2.condition->request_methods = {"delete", "get", "head", "options",
"patch", "post", "put"};
rules.push_back(rule2);
TestRule rule3 = CreateGenericRule(3);
rule3.condition->url_filter = "some_methods";
rule3.condition->request_methods = {"get", "put"};
rules.push_back(rule3);
TestRule rule4 = CreateGenericRule(4);
rule4.condition->url_filter = "all_methods_excluded";
rule4.condition->excluded_request_methods = {
"delete", "get", "head", "options", "patch", "post", "put"};
rules.push_back(rule4);
TestRule rule5 = CreateGenericRule(5);
rule5.condition->url_filter = "some_methods_excluded";
rule5.condition->excluded_request_methods = {"get", "put"};
rules.push_back(rule5);
ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(rules));
// Start a web socket test server.
net::SpawnedTestServer websocket_test_server(
net::SpawnedTestServer::TYPE_WS, net::GetWebSocketTestDataDirectory());
ASSERT_TRUE(websocket_test_server.Start());
std::string websocket_url =
websocket_test_server.GetURL("echo-with-no-extension").spec();
const char kOpenWebSocketsScript[] = R"(
{
const websocketUrl = "%s";
const testCases = ["default", "all_methods", "some_methods",
"all_methods_excluded", "some_methods_excluded"];
let blockedTestCases = [];
Promise.allSettled(
testCases.map(testCase =>
new Promise(resolve =>
{
let websocket = new WebSocket(websocketUrl + "?" + testCase);
websocket.addEventListener("open", event =>
{
websocket.close();
resolve();
});
websocket.addEventListener("error", event =>
{
blockedTestCases.push(testCase);
resolve();
});
})
)
).then(() =>
{
window.domAutomationController.send(blockedTestCases.sort().join());
});
}
)";
content::RenderFrameHost* main_frame = GetMainFrame();
std::string actual_blocked;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
main_frame,
base::StringPrintf(kOpenWebSocketsScript, websocket_url.c_str()),
&actual_blocked));
EXPECT_EQ("all_methods_excluded,default,some_methods_excluded",
actual_blocked);
}
// Tests that FLEDGE requests can be blocked by the declarativeNetRequest API, // Tests that FLEDGE requests can be blocked by the declarativeNetRequest API,
// and that if they try to redirect requests, the request is blocked, instead of // and that if they try to redirect requests, the request is blocked, instead of
// being redirected. // being redirected.

@@ -54,12 +54,12 @@ VerifyStatus GetVerifyStatus(const uint8_t* buffer,
// RulesetIndexer -------------------------------------------------------------- // RulesetIndexer --------------------------------------------------------------
const int RulesetIndexer::kIndexedFormatVersion = 30; const int RulesetIndexer::kIndexedFormatVersion = 31;
// This static assert is meant to catch cases where // This static assert is meant to catch cases where
// url_pattern_index::kUrlPatternIndexFormatVersion is incremented without // url_pattern_index::kUrlPatternIndexFormatVersion is incremented without
// updating RulesetIndexer::kIndexedFormatVersion. // updating RulesetIndexer::kIndexedFormatVersion.
static_assert(url_pattern_index::kUrlPatternIndexFormatVersion == 9, static_assert(url_pattern_index::kUrlPatternIndexFormatVersion == 10,
"kUrlPatternIndexFormatVersion has changed, make sure you've " "kUrlPatternIndexFormatVersion has changed, make sure you've "
"also updated RulesetIndexer::kIndexedFormatVersion above."); "also updated RulesetIndexer::kIndexedFormatVersion above.");

@@ -70,6 +70,7 @@ enum RequestMethod : ubyte (bit_flags) {
PATCH, PATCH,
POST, POST,
PUT, PUT,
NON_HTTP
// Note: Update the default value for `request_methods` field in UrlRule, on // Note: Update the default value for `request_methods` field in UrlRule, on
// adding/removing values from this enum. // adding/removing values from this enum.
} }
@@ -87,7 +88,7 @@ table UrlRule {
element_types : ushort = 8191; element_types : ushort = 8191;
// A bitmask of RequestMethod. Equals RequestMethod_ANY by default. // A bitmask of RequestMethod. Equals RequestMethod_ANY by default.
request_methods : ushort = 127; request_methods : ushort = 255;
// A bitmask of ActivationType. Disables all activation types by default. // A bitmask of ActivationType. Disables all activation types by default.
activation_types : ubyte = 0; activation_types : ubyte = 0;

@@ -85,7 +85,7 @@ int CompareDomains(base::StringPiece lhs_domain, base::StringPiece rhs_domain);
// Increase this value when introducing an incompatible change to the // Increase this value when introducing an incompatible change to the
// UrlPatternIndex schema (flat/url_pattern_index.fbs). url_pattern_index // UrlPatternIndex schema (flat/url_pattern_index.fbs). url_pattern_index
// clients can use this as a signal to rebuild rulesets. // clients can use this as a signal to rebuild rulesets.
constexpr int kUrlPatternIndexFormatVersion = 9; constexpr int kUrlPatternIndexFormatVersion = 10;
// The class used to construct an index over the URL patterns of a set of URL // The class used to construct an index over the URL patterns of a set of URL
// rules. The rules themselves need to be converted to FlatBuffers format by the // rules. The rules themselves need to be converted to FlatBuffers format by the

@@ -153,7 +153,7 @@ TEST_F(IndexedRulesetFormatVersionTest, CheckVersionUpdated) {
EXPECT_EQ(StripCommentsAndWhitespace(kFlatbufferSchemaExpected), EXPECT_EQ(StripCommentsAndWhitespace(kFlatbufferSchemaExpected),
StripCommentsAndWhitespace(flatbuffer_schema)) StripCommentsAndWhitespace(flatbuffer_schema))
<< "Schema change detected; update this test and the schema version."; << "Schema change detected; update this test and the schema version.";
EXPECT_EQ(21, GetIndexedRulesetFormatVersionForTesting()) EXPECT_EQ(22, GetIndexedRulesetFormatVersionForTesting())
<< "Update this test if you update the schema version."; << "Update this test if you update the schema version.";
} }

@@ -65,8 +65,12 @@ flat_rule::ElementType GetElementType(WebRequestResourceType web_request_type) {
} }
// Maps an HTTP request method string to flat_rule::RequestMethod. // Maps an HTTP request method string to flat_rule::RequestMethod.
// TODO(kzar): Return `flat_rule::RequestMethod_NONE` for non-HTTP requests. // Returns `flat::RequestMethod_NON_HTTP` for non-HTTP(s) requests.
flat_rule::RequestMethod GetRequestMethod(const std::string& method) { flat_rule::RequestMethod GetRequestMethod(bool http_or_https,
const std::string& method) {
if (!http_or_https)
return flat_rule::RequestMethod_NON_HTTP;
using net::HttpRequestHeaders; using net::HttpRequestHeaders;
static const base::NoDestructor< static const base::NoDestructor<
base::flat_map<base::StringPiece, flat_rule::RequestMethod>> base::flat_map<base::StringPiece, flat_rule::RequestMethod>>
@@ -173,7 +177,7 @@ RequestParams::RequestParams(const WebRequestInfo& info)
: url(&info.url), : url(&info.url),
first_party_origin(info.initiator.value_or(url::Origin())), first_party_origin(info.initiator.value_or(url::Origin())),
element_type(GetElementType(info.web_request_type)), element_type(GetElementType(info.web_request_type)),
method(GetRequestMethod(info.method)), method(GetRequestMethod(info.url.SchemeIsHTTPOrHTTPS(), info.method)),
parent_routing_id(info.parent_routing_id), parent_routing_id(info.parent_routing_id),
embedder_conditions_matcher(base::BindRepeating(DoEmbedderConditionsMatch, embedder_conditions_matcher(base::BindRepeating(DoEmbedderConditionsMatch,
info.frame_data.tab_id)) { info.frame_data.tab_id)) {

@@ -43,12 +43,12 @@ namespace dnr_api = api::declarative_net_request;
// url_pattern_index.fbs. Whenever an extension with an indexed ruleset format // url_pattern_index.fbs. Whenever an extension with an indexed ruleset format
// version different from the one currently used by Chrome is loaded, the // version different from the one currently used by Chrome is loaded, the
// extension ruleset will be reindexed. // extension ruleset will be reindexed.
constexpr int kIndexedRulesetFormatVersion = 21; constexpr int kIndexedRulesetFormatVersion = 22;
// This static assert is meant to catch cases where // This static assert is meant to catch cases where
// url_pattern_index::kUrlPatternIndexFormatVersion is incremented without // url_pattern_index::kUrlPatternIndexFormatVersion is incremented without
// updating kIndexedRulesetFormatVersion. // updating kIndexedRulesetFormatVersion.
static_assert(url_pattern_index::kUrlPatternIndexFormatVersion == 9, static_assert(url_pattern_index::kUrlPatternIndexFormatVersion == 10,
"kUrlPatternIndexFormatVersion has changed, make sure you've " "kUrlPatternIndexFormatVersion has changed, make sure you've "
"also updated kIndexedRulesetFormatVersion above."); "also updated kIndexedRulesetFormatVersion above.");

@@ -261,7 +261,10 @@ namespace declarativeNetRequest {
// List of HTTP request methods which the rule can match. An empty list is // List of HTTP request methods which the rule can match. An empty list is
// not allowed. // not allowed.
// Note: Non HTTP requests are considered to have the "get" request method. //
// Note: Specifying a <code>requestMethods</code> rule condition will also
// exclude non-HTTP(s) requests, whereas specifying
// <code>excludedRequestMethods</code> will not.
RequestMethod[]? requestMethods; RequestMethod[]? requestMethods;
// List of request methods which the rule won't match. Only one of // List of request methods which the rule won't match. Only one of