1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h"
10 #include "base/basictypes.h"
11 #include "base/json/json_reader.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/stl_util.h"
15 #include "base/test/values_test_util.h"
16 #include "base/values.h"
17 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
18 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
19 #include "chrome/common/extensions/extension_test_util.h"
20 #include "components/url_matcher/url_matcher_constants.h"
21 #include "content/public/test/test_browser_thread.h"
22 #include "net/base/request_priority.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest-message.h"
26 #include "testing/gtest/include/gtest/gtest.h"
29 using extension_test_util::LoadManifest
;
30 using extension_test_util::LoadManifestUnchecked
;
31 using testing::HasSubstr
;
32 using url_matcher::URLMatcher
;
35 const char kExtensionId
[] = "ext1";
36 const char kExtensionId2
[] = "ext2";
37 const char kRuleId1
[] = "rule1";
38 const char kRuleId2
[] = "rule2";
39 const char kRuleId3
[] = "rule3";
40 const char kRuleId4
[] = "rule4";
43 namespace extensions
{
45 namespace helpers
= extension_web_request_api_helpers
;
46 namespace keys
= declarative_webrequest_constants
;
47 namespace keys2
= url_matcher::url_matcher_constants
;
49 class TestWebRequestRulesRegistry
: public WebRequestRulesRegistry
{
51 TestWebRequestRulesRegistry(
52 scoped_refptr
<InfoMap
> extension_info_map
)
53 : WebRequestRulesRegistry(NULL
/*profile*/,
54 NULL
/* cache_delegate */,
56 num_clear_cache_calls_(0) {
57 SetExtensionInfoMapForTesting(extension_info_map
);
60 // Returns how often the in-memory caches of the renderers were instructed
62 int num_clear_cache_calls() const { return num_clear_cache_calls_
; }
64 // How many rules are there which have some conditions not triggered by URL
66 size_t RulesWithoutTriggers() const {
67 return rules_with_untriggered_conditions_for_test().size();
71 virtual ~TestWebRequestRulesRegistry() {}
73 virtual void ClearCacheOnNavigation() OVERRIDE
{
74 ++num_clear_cache_calls_
;
78 int num_clear_cache_calls_
;
81 class WebRequestRulesRegistryTest
: public testing::Test
{
83 WebRequestRulesRegistryTest()
84 : ui_(content::BrowserThread::UI
, &message_loop_
),
85 io_(content::BrowserThread::IO
, &message_loop_
) {}
87 virtual ~WebRequestRulesRegistryTest() {}
89 virtual void SetUp() OVERRIDE
;
91 virtual void TearDown() OVERRIDE
{
92 // Make sure that deletion traits of all registries are executed.
93 message_loop_
.RunUntilIdle();
96 // Returns a rule that roughly matches http://*.example.com and
97 // https://www.example.com and cancels it
98 linked_ptr
<RulesRegistry::Rule
> CreateRule1() {
99 base::ListValue
* scheme_http
= new base::ListValue();
100 scheme_http
->Append(new base::StringValue("http"));
101 base::DictionaryValue
* http_condition_dict
= new base::DictionaryValue();
102 http_condition_dict
->Set(keys2::kSchemesKey
, scheme_http
);
103 http_condition_dict
->SetString(keys2::kHostSuffixKey
, "example.com");
104 base::DictionaryValue http_condition_url_filter
;
105 http_condition_url_filter
.Set(keys::kUrlKey
, http_condition_dict
);
106 http_condition_url_filter
.SetString(keys::kInstanceTypeKey
,
107 keys::kRequestMatcherType
);
109 base::ListValue
* scheme_https
= new base::ListValue();
110 scheme_http
->Append(new base::StringValue("https"));
111 base::DictionaryValue
* https_condition_dict
= new base::DictionaryValue();
112 https_condition_dict
->Set(keys2::kSchemesKey
, scheme_https
);
113 https_condition_dict
->SetString(keys2::kHostSuffixKey
, "example.com");
114 https_condition_dict
->SetString(keys2::kHostPrefixKey
, "www");
115 base::DictionaryValue https_condition_url_filter
;
116 https_condition_url_filter
.Set(keys::kUrlKey
, https_condition_dict
);
117 https_condition_url_filter
.SetString(keys::kInstanceTypeKey
,
118 keys::kRequestMatcherType
);
120 base::DictionaryValue action_dict
;
121 action_dict
.SetString(keys::kInstanceTypeKey
, keys::kCancelRequestType
);
123 linked_ptr
<RulesRegistry::Rule
> rule(new RulesRegistry::Rule
);
124 rule
->id
.reset(new std::string(kRuleId1
));
125 rule
->priority
.reset(new int(100));
126 rule
->actions
.push_back(linked_ptr
<base::Value
>(action_dict
.DeepCopy()));
127 rule
->conditions
.push_back(
128 linked_ptr
<base::Value
>(http_condition_url_filter
.DeepCopy()));
129 rule
->conditions
.push_back(
130 linked_ptr
<base::Value
>(https_condition_url_filter
.DeepCopy()));
134 // Returns a rule that matches anything and cancels it.
135 linked_ptr
<RulesRegistry::Rule
> CreateRule2() {
136 base::DictionaryValue condition_dict
;
137 condition_dict
.SetString(keys::kInstanceTypeKey
, keys::kRequestMatcherType
);
139 base::DictionaryValue action_dict
;
140 action_dict
.SetString(keys::kInstanceTypeKey
, keys::kCancelRequestType
);
142 linked_ptr
<RulesRegistry::Rule
> rule(new RulesRegistry::Rule
);
143 rule
->id
.reset(new std::string(kRuleId2
));
144 rule
->priority
.reset(new int(100));
145 rule
->actions
.push_back(linked_ptr
<base::Value
>(action_dict
.DeepCopy()));
146 rule
->conditions
.push_back(
147 linked_ptr
<base::Value
>(condition_dict
.DeepCopy()));
151 linked_ptr
<RulesRegistry::Rule
> CreateRedirectRule(
152 const std::string
& destination
) {
153 base::DictionaryValue condition_dict
;
154 condition_dict
.SetString(keys::kInstanceTypeKey
, keys::kRequestMatcherType
);
156 base::DictionaryValue action_dict
;
157 action_dict
.SetString(keys::kInstanceTypeKey
, keys::kRedirectRequestType
);
158 action_dict
.SetString(keys::kRedirectUrlKey
, destination
);
160 linked_ptr
<RulesRegistry::Rule
> rule(new RulesRegistry::Rule
);
161 rule
->id
.reset(new std::string(kRuleId3
));
162 rule
->priority
.reset(new int(100));
163 rule
->actions
.push_back(linked_ptr
<base::Value
>(action_dict
.DeepCopy()));
164 rule
->conditions
.push_back(
165 linked_ptr
<base::Value
>(condition_dict
.DeepCopy()));
169 // Create a rule to ignore all other rules for a destination that
170 // contains index.html.
171 linked_ptr
<RulesRegistry::Rule
> CreateIgnoreRule() {
172 base::DictionaryValue condition_dict
;
173 base::DictionaryValue
* http_condition_dict
= new base::DictionaryValue();
174 http_condition_dict
->SetString(keys2::kPathContainsKey
, "index.html");
175 condition_dict
.SetString(keys::kInstanceTypeKey
, keys::kRequestMatcherType
);
176 condition_dict
.Set(keys::kUrlKey
, http_condition_dict
);
178 base::DictionaryValue action_dict
;
179 action_dict
.SetString(keys::kInstanceTypeKey
, keys::kIgnoreRulesType
);
180 action_dict
.SetInteger(keys::kLowerPriorityThanKey
, 150);
182 linked_ptr
<RulesRegistry::Rule
> rule(new RulesRegistry::Rule
);
183 rule
->id
.reset(new std::string(kRuleId4
));
184 rule
->priority
.reset(new int(200));
185 rule
->actions
.push_back(linked_ptr
<base::Value
>(action_dict
.DeepCopy()));
186 rule
->conditions
.push_back(
187 linked_ptr
<base::Value
>(condition_dict
.DeepCopy()));
191 // Create a condition with the attributes specified. An example value of
192 // |attributes| is: "\"resourceType\": [\"stylesheet\"], \n".
193 linked_ptr
<base::Value
> CreateCondition(const std::string
& attributes
) {
194 std::string json_description
=
196 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n";
197 json_description
+= attributes
;
198 json_description
+= "}";
200 return linked_ptr
<base::Value
>(
201 base::test::ParseJson(json_description
).release());
204 // Create a rule with the ID |rule_id| and with conditions created from the
205 // |attributes| specified (one entry one condition). An example value of a
206 // string from |attributes| is: "\"resourceType\": [\"stylesheet\"], \n".
207 linked_ptr
<RulesRegistry::Rule
> CreateCancellingRule(
209 const std::vector
<const std::string
*>& attributes
) {
210 base::DictionaryValue action_dict
;
211 action_dict
.SetString(keys::kInstanceTypeKey
, keys::kCancelRequestType
);
213 linked_ptr
<RulesRegistry::Rule
> rule(new RulesRegistry::Rule
);
214 rule
->id
.reset(new std::string(rule_id
));
215 rule
->priority
.reset(new int(1));
216 rule
->actions
.push_back(linked_ptr
<base::Value
>(action_dict
.DeepCopy()));
217 for (std::vector
<const std::string
*>::const_iterator it
=
219 it
!= attributes
.end(); ++it
)
220 rule
->conditions
.push_back(CreateCondition(**it
));
225 base::MessageLoopForIO message_loop_
;
226 content::TestBrowserThread ui_
;
227 content::TestBrowserThread io_
;
228 // Two extensions with host permissions for all URLs and the DWR permission.
229 // Installation times will be so that |extension_| is older than
231 scoped_refptr
<Extension
> extension_
;
232 scoped_refptr
<Extension
> extension2_
;
233 scoped_refptr
<InfoMap
> extension_info_map_
;
236 void WebRequestRulesRegistryTest::SetUp() {
237 testing::Test::SetUp();
240 extension_
= LoadManifestUnchecked("permissions",
241 "web_request_all_host_permissions.json",
242 Manifest::INVALID_LOCATION
,
246 ASSERT_TRUE(extension_
.get()) << error
;
247 extension2_
= LoadManifestUnchecked("permissions",
248 "web_request_all_host_permissions.json",
249 Manifest::INVALID_LOCATION
,
253 ASSERT_TRUE(extension2_
.get()) << error
;
254 extension_info_map_
= new InfoMap
;
255 ASSERT_TRUE(extension_info_map_
.get());
256 extension_info_map_
->AddExtension(extension_
.get(),
257 base::Time() + base::TimeDelta::FromDays(1),
258 false /*incognito_enabled*/,
259 false /*notifications_disabled*/);
260 extension_info_map_
->AddExtension(extension2_
.get(),
261 base::Time() + base::TimeDelta::FromDays(2),
262 false /*incognito_enabled*/,
263 false /*notifications_disabled*/);
267 TEST_F(WebRequestRulesRegistryTest
, AddRulesImpl
) {
268 scoped_refptr
<TestWebRequestRulesRegistry
> registry(
269 new TestWebRequestRulesRegistry(extension_info_map_
));
272 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules
;
273 rules
.push_back(CreateRule1());
274 rules
.push_back(CreateRule2());
276 error
= registry
->AddRules(kExtensionId
, rules
);
277 EXPECT_EQ("", error
);
278 EXPECT_EQ(1, registry
->num_clear_cache_calls());
280 std::set
<const WebRequestRule
*> matches
;
282 GURL
http_url("http://www.example.com");
283 net::TestURLRequestContext context
;
284 net::TestURLRequest
http_request(
285 http_url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
286 WebRequestData
request_data(&http_request
, ON_BEFORE_REQUEST
);
287 matches
= registry
->GetMatches(request_data
);
288 EXPECT_EQ(2u, matches
.size());
290 std::set
<WebRequestRule::GlobalRuleId
> matches_ids
;
291 for (std::set
<const WebRequestRule
*>::const_iterator it
= matches
.begin();
292 it
!= matches
.end(); ++it
)
293 matches_ids
.insert((*it
)->id());
294 EXPECT_TRUE(ContainsKey(matches_ids
, std::make_pair(kExtensionId
, kRuleId1
)));
295 EXPECT_TRUE(ContainsKey(matches_ids
, std::make_pair(kExtensionId
, kRuleId2
)));
297 GURL
foobar_url("http://www.foobar.com");
298 net::TestURLRequest
foobar_request(
299 foobar_url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
300 request_data
.request
= &foobar_request
;
301 matches
= registry
->GetMatches(request_data
);
302 EXPECT_EQ(1u, matches
.size());
303 WebRequestRule::GlobalRuleId expected_pair
=
304 std::make_pair(kExtensionId
, kRuleId2
);
305 EXPECT_EQ(expected_pair
, (*matches
.begin())->id());
308 TEST_F(WebRequestRulesRegistryTest
, RemoveRulesImpl
) {
309 scoped_refptr
<TestWebRequestRulesRegistry
> registry(
310 new TestWebRequestRulesRegistry(extension_info_map_
));
313 // Setup RulesRegistry to contain two rules.
314 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add
;
315 rules_to_add
.push_back(CreateRule1());
316 rules_to_add
.push_back(CreateRule2());
317 error
= registry
->AddRules(kExtensionId
, rules_to_add
);
318 EXPECT_EQ("", error
);
319 EXPECT_EQ(1, registry
->num_clear_cache_calls());
321 // Verify initial state.
322 std::vector
<linked_ptr
<RulesRegistry::Rule
> > registered_rules
;
323 registry
->GetAllRules(kExtensionId
, ®istered_rules
);
324 EXPECT_EQ(2u, registered_rules
.size());
325 EXPECT_EQ(1u, registry
->RulesWithoutTriggers());
327 // Remove first rule.
328 std::vector
<std::string
> rules_to_remove
;
329 rules_to_remove
.push_back(kRuleId1
);
330 error
= registry
->RemoveRules(kExtensionId
, rules_to_remove
);
331 EXPECT_EQ("", error
);
332 EXPECT_EQ(2, registry
->num_clear_cache_calls());
334 // Verify that only one rule is left.
335 registered_rules
.clear();
336 registry
->GetAllRules(kExtensionId
, ®istered_rules
);
337 EXPECT_EQ(1u, registered_rules
.size());
338 EXPECT_EQ(1u, registry
->RulesWithoutTriggers());
340 // Now rules_to_remove contains both rules, i.e. one that does not exist in
341 // the rules registry anymore. Effectively we only remove the second rule.
342 rules_to_remove
.push_back(kRuleId2
);
343 error
= registry
->RemoveRules(kExtensionId
, rules_to_remove
);
344 EXPECT_EQ("", error
);
345 EXPECT_EQ(3, registry
->num_clear_cache_calls());
347 // Verify that everything is gone.
348 registered_rules
.clear();
349 registry
->GetAllRules(kExtensionId
, ®istered_rules
);
350 EXPECT_EQ(0u, registered_rules
.size());
351 EXPECT_EQ(0u, registry
->RulesWithoutTriggers());
353 EXPECT_TRUE(registry
->IsEmpty());
356 TEST_F(WebRequestRulesRegistryTest
, RemoveAllRulesImpl
) {
357 scoped_refptr
<TestWebRequestRulesRegistry
> registry(
358 new TestWebRequestRulesRegistry(extension_info_map_
));
361 // Setup RulesRegistry to contain two rules, one for each extension.
362 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add(1);
363 rules_to_add
[0] = CreateRule1();
364 error
= registry
->AddRules(kExtensionId
, rules_to_add
);
365 EXPECT_EQ("", error
);
366 EXPECT_EQ(1, registry
->num_clear_cache_calls());
368 rules_to_add
[0] = CreateRule2();
369 error
= registry
->AddRules(kExtensionId2
, rules_to_add
);
370 EXPECT_EQ("", error
);
371 EXPECT_EQ(2, registry
->num_clear_cache_calls());
373 // Verify initial state.
374 std::vector
<linked_ptr
<RulesRegistry::Rule
> > registered_rules
;
375 registry
->GetAllRules(kExtensionId
, ®istered_rules
);
376 EXPECT_EQ(1u, registered_rules
.size());
377 registered_rules
.clear();
378 registry
->GetAllRules(kExtensionId2
, ®istered_rules
);
379 EXPECT_EQ(1u, registered_rules
.size());
381 // Remove rule of first extension.
382 error
= registry
->RemoveAllRules(kExtensionId
);
383 EXPECT_EQ("", error
);
384 EXPECT_EQ(3, registry
->num_clear_cache_calls());
386 // Verify that only the first rule is deleted.
387 registered_rules
.clear();
388 registry
->GetAllRules(kExtensionId
, ®istered_rules
);
389 EXPECT_EQ(0u, registered_rules
.size());
390 registered_rules
.clear();
391 registry
->GetAllRules(kExtensionId2
, ®istered_rules
);
392 EXPECT_EQ(1u, registered_rules
.size());
394 // Test removing rules if none exist.
395 error
= registry
->RemoveAllRules(kExtensionId
);
396 EXPECT_EQ("", error
);
397 EXPECT_EQ(4, registry
->num_clear_cache_calls());
399 // Remove rule from second extension.
400 error
= registry
->RemoveAllRules(kExtensionId2
);
401 EXPECT_EQ("", error
);
402 EXPECT_EQ(5, registry
->num_clear_cache_calls());
404 EXPECT_TRUE(registry
->IsEmpty());
407 // Test precedences between extensions.
408 TEST_F(WebRequestRulesRegistryTest
, Precedences
) {
409 scoped_refptr
<WebRequestRulesRegistry
> registry(
410 new TestWebRequestRulesRegistry(extension_info_map_
));
413 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add_1(1);
414 rules_to_add_1
[0] = CreateRedirectRule("http://www.foo.com");
415 error
= registry
->AddRules(kExtensionId
, rules_to_add_1
);
416 EXPECT_EQ("", error
);
418 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add_2(1);
419 rules_to_add_2
[0] = CreateRedirectRule("http://www.bar.com");
420 error
= registry
->AddRules(kExtensionId2
, rules_to_add_2
);
421 EXPECT_EQ("", error
);
423 GURL
url("http://www.google.com");
424 net::TestURLRequestContext context
;
425 net::TestURLRequest
request(url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
426 WebRequestData
request_data(&request
, ON_BEFORE_REQUEST
);
427 std::list
<LinkedPtrEventResponseDelta
> deltas
=
428 registry
->CreateDeltas(NULL
, request_data
, false);
430 // The second extension is installed later and will win for this reason
431 // in conflict resolution.
432 ASSERT_EQ(2u, deltas
.size());
433 deltas
.sort(&helpers::InDecreasingExtensionInstallationTimeOrder
);
435 std::list
<LinkedPtrEventResponseDelta
>::iterator i
= deltas
.begin();
436 LinkedPtrEventResponseDelta winner
= *i
++;
437 LinkedPtrEventResponseDelta loser
= *i
;
439 EXPECT_EQ(kExtensionId2
, winner
->extension_id
);
440 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(2),
441 winner
->extension_install_time
);
442 EXPECT_EQ(GURL("http://www.bar.com"), winner
->new_url
);
444 EXPECT_EQ(kExtensionId
, loser
->extension_id
);
445 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(1),
446 loser
->extension_install_time
);
447 EXPECT_EQ(GURL("http://www.foo.com"), loser
->new_url
);
450 // Test priorities of rules within one extension.
451 TEST_F(WebRequestRulesRegistryTest
, Priorities
) {
452 scoped_refptr
<WebRequestRulesRegistry
> registry(
453 new TestWebRequestRulesRegistry(extension_info_map_
));
456 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add_1(1);
457 rules_to_add_1
[0] = CreateRedirectRule("http://www.foo.com");
458 error
= registry
->AddRules(kExtensionId
, rules_to_add_1
);
459 EXPECT_EQ("", error
);
461 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add_2(1);
462 rules_to_add_2
[0] = CreateRedirectRule("http://www.bar.com");
463 error
= registry
->AddRules(kExtensionId2
, rules_to_add_2
);
464 EXPECT_EQ("", error
);
466 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules_to_add_3(1);
467 rules_to_add_3
[0] = CreateIgnoreRule();
468 error
= registry
->AddRules(kExtensionId
, rules_to_add_3
);
469 EXPECT_EQ("", error
);
471 GURL
url("http://www.google.com/index.html");
472 net::TestURLRequestContext context
;
473 net::TestURLRequest
request(url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
474 WebRequestData
request_data(&request
, ON_BEFORE_REQUEST
);
475 std::list
<LinkedPtrEventResponseDelta
> deltas
=
476 registry
->CreateDeltas(NULL
, request_data
, false);
478 // The redirect by the first extension is ignored due to the ignore rule.
479 ASSERT_EQ(1u, deltas
.size());
480 LinkedPtrEventResponseDelta effective_rule
= *(deltas
.begin());
482 EXPECT_EQ(kExtensionId2
, effective_rule
->extension_id
);
483 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(2),
484 effective_rule
->extension_install_time
);
485 EXPECT_EQ(GURL("http://www.bar.com"), effective_rule
->new_url
);
488 // Test ignoring of rules by tag.
489 TEST_F(WebRequestRulesRegistryTest
, IgnoreRulesByTag
) {
490 const char kRule1
[] =
492 " \"id\": \"rule1\", \n"
493 " \"tags\": [\"non_matching_tag\", \"ignore_tag\"], \n"
494 " \"conditions\": [ \n"
496 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
497 " \"url\": {\"hostSuffix\": \"foo.com\"} \n"
502 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
503 " \"redirectUrl\": \"http://bar.com\" \n"
506 " \"priority\": 200 \n"
509 const char kRule2
[] =
511 " \"id\": \"rule2\", \n"
512 " \"conditions\": [ \n"
514 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
515 " \"url\": {\"pathPrefix\": \"/test\"} \n"
520 " \"instanceType\": \"declarativeWebRequest.IgnoreRules\", \n"
521 " \"hasTag\": \"ignore_tag\" \n"
524 " \"priority\": 300 \n"
527 scoped_ptr
<base::Value
> value1(base::JSONReader::Read(kRule1
));
528 ASSERT_TRUE(value1
.get());
529 scoped_ptr
<base::Value
> value2(base::JSONReader::Read(kRule2
));
530 ASSERT_TRUE(value2
.get());
532 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules
;
533 rules
.push_back(make_linked_ptr(new RulesRegistry::Rule
));
534 rules
.push_back(make_linked_ptr(new RulesRegistry::Rule
));
535 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value1
, rules
[0].get()));
536 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value2
, rules
[1].get()));
538 scoped_refptr
<WebRequestRulesRegistry
> registry(
539 new TestWebRequestRulesRegistry(extension_info_map_
));
540 std::string error
= registry
->AddRulesImpl(kExtensionId
, rules
);
541 EXPECT_EQ("", error
);
542 EXPECT_FALSE(registry
->IsEmpty());
544 GURL
url("http://www.foo.com/test");
545 net::TestURLRequestContext context
;
546 net::TestURLRequest
request(url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
547 WebRequestData
request_data(&request
, ON_BEFORE_REQUEST
);
548 std::list
<LinkedPtrEventResponseDelta
> deltas
=
549 registry
->CreateDeltas(NULL
, request_data
, false);
551 // The redirect by the redirect rule is ignored due to the ignore rule.
552 std::set
<const WebRequestRule
*> matches
= registry
->GetMatches(request_data
);
553 EXPECT_EQ(2u, matches
.size());
554 ASSERT_EQ(0u, deltas
.size());
557 // Test that rules failing IsFulfilled on their conditions are never returned by
559 TEST_F(WebRequestRulesRegistryTest
, GetMatchesCheckFulfilled
) {
560 scoped_refptr
<TestWebRequestRulesRegistry
> registry(
561 new TestWebRequestRulesRegistry(extension_info_map_
));
562 const std::string
kMatchingUrlAttribute(
563 "\"url\": { \"pathContains\": \"\" }, \n");
564 const std::string
kNonMatchingNonUrlAttribute(
565 "\"resourceType\": [\"stylesheet\"], \n");
566 const std::string
kBothAttributes(kMatchingUrlAttribute
+
567 kNonMatchingNonUrlAttribute
);
569 std::vector
<const std::string
*> attributes
;
570 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules
;
572 // Rules 1 and 2 have one condition, neither of them should fire.
573 attributes
.push_back(&kNonMatchingNonUrlAttribute
);
574 rules
.push_back(CreateCancellingRule(kRuleId1
, attributes
));
577 attributes
.push_back(&kBothAttributes
);
578 rules
.push_back(CreateCancellingRule(kRuleId2
, attributes
));
580 // Rule 3 has two conditions, one with a matching URL attribute, and one
581 // with a non-matching non-URL attribute.
583 attributes
.push_back(&kMatchingUrlAttribute
);
584 attributes
.push_back(&kNonMatchingNonUrlAttribute
);
585 rules
.push_back(CreateCancellingRule(kRuleId3
, attributes
));
587 error
= registry
->AddRules(kExtensionId
, rules
);
588 EXPECT_EQ("", error
);
589 EXPECT_EQ(1, registry
->num_clear_cache_calls());
591 std::set
<const WebRequestRule
*> matches
;
593 GURL
http_url("http://www.example.com");
594 net::TestURLRequestContext context
;
595 net::TestURLRequest
http_request(
596 http_url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
597 WebRequestData
request_data(&http_request
, ON_BEFORE_REQUEST
);
598 matches
= registry
->GetMatches(request_data
);
599 EXPECT_EQ(1u, matches
.size());
600 WebRequestRule::GlobalRuleId expected_pair
= std::make_pair(kExtensionId
,
602 EXPECT_EQ(expected_pair
, (*matches
.begin())->id());
605 // Test that the url and firstPartyForCookiesUrl attributes are evaluated
606 // against corresponding URLs. Tested on requests where these URLs actually
608 TEST_F(WebRequestRulesRegistryTest
, GetMatchesDifferentUrls
) {
609 scoped_refptr
<TestWebRequestRulesRegistry
> registry(
610 new TestWebRequestRulesRegistry(extension_info_map_
));
611 const std::string
kUrlAttribute(
612 "\"url\": { \"hostContains\": \"url\" }, \n");
613 const std::string
kFirstPartyUrlAttribute(
614 "\"firstPartyForCookiesUrl\": { \"hostContains\": \"fpfc\" }, \n");
616 std::vector
<const std::string
*> attributes
;
617 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules
;
619 // Rule 1 has one condition, with a url attribute
620 attributes
.push_back(&kUrlAttribute
);
621 rules
.push_back(CreateCancellingRule(kRuleId1
, attributes
));
623 // Rule 2 has one condition, with a firstPartyForCookiesUrl attribute
625 attributes
.push_back(&kFirstPartyUrlAttribute
);
626 rules
.push_back(CreateCancellingRule(kRuleId2
, attributes
));
628 error
= registry
->AddRules(kExtensionId
, rules
);
629 EXPECT_EQ("", error
);
630 EXPECT_EQ(1, registry
->num_clear_cache_calls());
632 std::set
<const WebRequestRule
*> matches
;
634 const GURL urls
[] = {
635 GURL("http://url.example.com"), // matching
636 GURL("http://www.example.com") // non-matching
638 const GURL firstPartyUrls
[] = {
639 GURL("http://www.example.com"), // non-matching
640 GURL("http://fpfc.example.com") // matching
642 // Which rules should match in subsequent test iterations.
643 const char* matchingRuleIds
[] = { kRuleId1
, kRuleId2
};
644 COMPILE_ASSERT(arraysize(urls
) == arraysize(firstPartyUrls
),
645 urls_and_firstPartyUrls_need_to_have_the_same_size
);
646 COMPILE_ASSERT(arraysize(urls
) == arraysize(matchingRuleIds
),
647 urls_and_matchingRuleIds_need_to_have_the_same_size
);
648 net::TestURLRequestContext context
;
650 for (size_t i
= 0; i
< arraysize(matchingRuleIds
); ++i
) {
651 // Construct the inputs.
652 net::TestURLRequest
http_request(
653 urls
[i
], net::DEFAULT_PRIORITY
, NULL
, &context
);
654 WebRequestData
request_data(&http_request
, ON_BEFORE_REQUEST
);
655 http_request
.set_first_party_for_cookies(firstPartyUrls
[i
]);
656 // Now run both rules on the input.
657 matches
= registry
->GetMatches(request_data
);
658 SCOPED_TRACE(testing::Message("i = ") << i
<< ", rule id = "
659 << matchingRuleIds
[i
]);
660 // Make sure that the right rule succeeded.
661 EXPECT_EQ(1u, matches
.size());
662 EXPECT_EQ(WebRequestRule::GlobalRuleId(std::make_pair(kExtensionId
,
663 matchingRuleIds
[i
])),
664 (*matches
.begin())->id());
668 TEST(WebRequestRulesRegistrySimpleTest
, StageChecker
) {
669 // The contentType condition can only be evaluated during ON_HEADERS_RECEIVED
670 // but the SetRequestHeader action can only be executed during
671 // ON_BEFORE_SEND_HEADERS.
672 // Therefore, this is an inconsistent rule that needs to be flagged.
675 " \"id\": \"rule1\", \n"
676 " \"conditions\": [ \n"
678 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
679 " \"url\": {\"hostSuffix\": \"foo.com\"}, \n"
680 " \"contentType\": [\"image/jpeg\"] \n"
685 " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\",\n"
686 " \"name\": \"Content-Type\", \n"
687 " \"value\": \"text/plain\" \n"
690 " \"priority\": 200 \n"
693 scoped_ptr
<base::Value
> value(base::JSONReader::Read(kRule
));
696 RulesRegistry::Rule rule
;
697 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value
, &rule
));
701 scoped_ptr
<WebRequestConditionSet
> conditions
=
702 WebRequestConditionSet::Create(
703 NULL
, matcher
.condition_factory(), rule
.conditions
, &error
);
704 ASSERT_TRUE(error
.empty()) << error
;
705 ASSERT_TRUE(conditions
);
707 bool bad_message
= false;
708 scoped_ptr
<WebRequestActionSet
> actions
=
709 WebRequestActionSet::Create(NULL
, rule
.actions
, &error
, &bad_message
);
710 ASSERT_TRUE(error
.empty()) << error
;
711 ASSERT_FALSE(bad_message
);
712 ASSERT_TRUE(actions
);
714 EXPECT_FALSE(WebRequestRulesRegistry::StageChecker(
715 conditions
.get(), actions
.get(), &error
));
716 EXPECT_THAT(error
, HasSubstr("no time in the request life-cycle"));
717 EXPECT_THAT(error
, HasSubstr(actions
->actions().back()->GetName()));
720 TEST(WebRequestRulesRegistrySimpleTest
, HostPermissionsChecker
) {
721 const char kAction
[] = // This action requires all URLs host permission.
723 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
724 " \"redirectUrl\": \"http://bar.com\" \n"
726 scoped_ptr
<base::Value
> action_value(base::JSONReader::Read(kAction
));
727 ASSERT_TRUE(action_value
);
729 WebRequestActionSet::AnyVector actions
;
730 actions
.push_back(linked_ptr
<base::Value
>(action_value
.release()));
731 ASSERT_TRUE(actions
.back().get());
734 bool bad_message
= false;
735 scoped_ptr
<WebRequestActionSet
> action_set(
736 WebRequestActionSet::Create(NULL
, actions
, &error
, &bad_message
));
737 ASSERT_TRUE(error
.empty()) << error
;
738 ASSERT_FALSE(bad_message
);
739 ASSERT_TRUE(action_set
);
741 scoped_refptr
<Extension
> extension_no_url(
742 LoadManifest("permissions", "web_request_no_host.json"));
743 scoped_refptr
<Extension
> extension_some_urls(
744 LoadManifest("permissions", "web_request_com_host_permissions.json"));
745 scoped_refptr
<Extension
> extension_all_urls(
746 LoadManifest("permissions", "web_request_all_host_permissions.json"));
748 EXPECT_TRUE(WebRequestRulesRegistry::HostPermissionsChecker(
749 extension_all_urls
.get(), action_set
.get(), &error
));
750 EXPECT_TRUE(error
.empty()) << error
;
752 EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker(
753 extension_some_urls
.get(), action_set
.get(), &error
));
754 EXPECT_THAT(error
, HasSubstr("permission for all"));
755 EXPECT_THAT(error
, HasSubstr(action_set
->actions().back()->GetName()));
757 EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker(
758 extension_no_url
.get(), action_set
.get(), &error
));
759 EXPECT_THAT(error
, HasSubstr("permission for all"));
760 EXPECT_THAT(error
, HasSubstr(action_set
->actions().back()->GetName()));
763 TEST_F(WebRequestRulesRegistryTest
, CheckOriginAndPathRegEx
) {
766 " \"id\": \"rule1\", \n"
767 " \"conditions\": [ \n"
769 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
770 " \"url\": {\"originAndPathMatches\": \"fo+.com\"} \n"
775 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
776 " \"redirectUrl\": \"http://bar.com\" \n"
779 " \"priority\": 200 \n"
782 scoped_ptr
<base::Value
> value(base::JSONReader::Read(kRule
));
783 ASSERT_TRUE(value
.get());
785 std::vector
<linked_ptr
<RulesRegistry::Rule
> > rules
;
786 rules
.push_back(make_linked_ptr(new RulesRegistry::Rule
));
787 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value
, rules
.back().get()));
789 scoped_refptr
<WebRequestRulesRegistry
> registry(
790 new TestWebRequestRulesRegistry(extension_info_map_
));
793 std::string error
= registry
->AddRulesImpl(kExtensionId
, rules
);
794 EXPECT_EQ("", error
);
796 net::TestURLRequestContext context
;
797 std::list
<LinkedPtrEventResponseDelta
> deltas
;
799 // No match because match is in the query parameter.
800 GURL
url1("http://bar.com/index.html?foo.com");
801 net::TestURLRequest
request1(url1
, net::DEFAULT_PRIORITY
, NULL
, &context
);
802 WebRequestData
request_data1(&request1
, ON_BEFORE_REQUEST
);
803 deltas
= registry
->CreateDeltas(NULL
, request_data1
, false);
804 EXPECT_EQ(0u, deltas
.size());
806 // This is a correct match.
807 GURL
url2("http://foo.com/index.html");
808 net::TestURLRequest
request2(url2
, net::DEFAULT_PRIORITY
, NULL
, &context
);
809 WebRequestData
request_data2(&request2
, ON_BEFORE_REQUEST
);
810 deltas
= registry
->CreateDeltas(NULL
, request_data2
, false);
811 EXPECT_EQ(1u, deltas
.size());
814 } // namespace extensions