Enable Enterprise enrollment on desktop builds.
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_webrequest / webrequest_rules_registry_unittest.cc
blob0efc9274c26b9c66fc177b3cac73c26a0555a203
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"
7 #include <string>
8 #include <vector>
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"
28 using base::Value;
29 using extension_test_util::LoadManifest;
30 using extension_test_util::LoadManifestUnchecked;
31 using testing::HasSubstr;
32 using url_matcher::URLMatcher;
34 namespace {
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";
41 } // namespace
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 {
50 public:
51 TestWebRequestRulesRegistry(
52 scoped_refptr<InfoMap> extension_info_map)
53 : WebRequestRulesRegistry(NULL /*profile*/,
54 NULL /* cache_delegate */,
55 WebViewKey(0, 0)),
56 num_clear_cache_calls_(0) {
57 SetExtensionInfoMapForTesting(extension_info_map);
60 // Returns how often the in-memory caches of the renderers were instructed
61 // to be cleared.
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
65 // matches.
66 size_t RulesWithoutTriggers() const {
67 return rules_with_untriggered_conditions_for_test().size();
70 protected:
71 virtual ~TestWebRequestRulesRegistry() {}
73 virtual void ClearCacheOnNavigation() OVERRIDE {
74 ++num_clear_cache_calls_;
77 private:
78 int num_clear_cache_calls_;
81 class WebRequestRulesRegistryTest : public testing::Test {
82 public:
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()));
131 return rule;
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()));
148 return rule;
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()));
166 return rule;
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()));
188 return rule;
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 =
195 "{ \n"
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(
208 const char* rule_id,
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 =
218 attributes.begin();
219 it != attributes.end(); ++it)
220 rule->conditions.push_back(CreateCondition(**it));
221 return rule;
224 protected:
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
230 // |extension2_|.
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();
239 std::string error;
240 extension_ = LoadManifestUnchecked("permissions",
241 "web_request_all_host_permissions.json",
242 Manifest::INVALID_LOCATION,
243 Extension::NO_FLAGS,
244 kExtensionId,
245 &error);
246 ASSERT_TRUE(extension_.get()) << error;
247 extension2_ = LoadManifestUnchecked("permissions",
248 "web_request_all_host_permissions.json",
249 Manifest::INVALID_LOCATION,
250 Extension::NO_FLAGS,
251 kExtensionId2,
252 &error);
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_));
270 std::string error;
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_));
311 std::string error;
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, &registered_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, &registered_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, &registered_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_));
359 std::string error;
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, &registered_rules);
376 EXPECT_EQ(1u, registered_rules.size());
377 registered_rules.clear();
378 registry->GetAllRules(kExtensionId2, &registered_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, &registered_rules);
389 EXPECT_EQ(0u, registered_rules.size());
390 registered_rules.clear();
391 registry->GetAllRules(kExtensionId2, &registered_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_));
411 std::string error;
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_));
454 std::string error;
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[] =
491 "{ \n"
492 " \"id\": \"rule1\", \n"
493 " \"tags\": [\"non_matching_tag\", \"ignore_tag\"], \n"
494 " \"conditions\": [ \n"
495 " { \n"
496 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
497 " \"url\": {\"hostSuffix\": \"foo.com\"} \n"
498 " } \n"
499 " ], \n"
500 " \"actions\": [ \n"
501 " { \n"
502 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
503 " \"redirectUrl\": \"http://bar.com\" \n"
504 " } \n"
505 " ], \n"
506 " \"priority\": 200 \n"
507 "} ";
509 const char kRule2[] =
510 "{ \n"
511 " \"id\": \"rule2\", \n"
512 " \"conditions\": [ \n"
513 " { \n"
514 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
515 " \"url\": {\"pathPrefix\": \"/test\"} \n"
516 " } \n"
517 " ], \n"
518 " \"actions\": [ \n"
519 " { \n"
520 " \"instanceType\": \"declarativeWebRequest.IgnoreRules\", \n"
521 " \"hasTag\": \"ignore_tag\" \n"
522 " } \n"
523 " ], \n"
524 " \"priority\": 300 \n"
525 "} ";
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
558 // GetMatches.
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);
568 std::string error;
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));
576 attributes.clear();
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.
582 attributes.clear();
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,
601 kRuleId3);
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
607 // differ.
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");
615 std::string error;
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
624 attributes.clear();
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.
673 const char kRule[] =
674 "{ \n"
675 " \"id\": \"rule1\", \n"
676 " \"conditions\": [ \n"
677 " { \n"
678 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
679 " \"url\": {\"hostSuffix\": \"foo.com\"}, \n"
680 " \"contentType\": [\"image/jpeg\"] \n"
681 " } \n"
682 " ], \n"
683 " \"actions\": [ \n"
684 " { \n"
685 " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\",\n"
686 " \"name\": \"Content-Type\", \n"
687 " \"value\": \"text/plain\" \n"
688 " } \n"
689 " ], \n"
690 " \"priority\": 200 \n"
691 "} ";
693 scoped_ptr<base::Value> value(base::JSONReader::Read(kRule));
694 ASSERT_TRUE(value);
696 RulesRegistry::Rule rule;
697 ASSERT_TRUE(RulesRegistry::Rule::Populate(*value, &rule));
699 std::string error;
700 URLMatcher matcher;
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.
722 "{ \n"
723 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
724 " \"redirectUrl\": \"http://bar.com\" \n"
725 "} ";
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());
733 std::string error;
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) {
764 const char kRule[] =
765 "{ \n"
766 " \"id\": \"rule1\", \n"
767 " \"conditions\": [ \n"
768 " { \n"
769 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
770 " \"url\": {\"originAndPathMatches\": \"fo+.com\"} \n"
771 " } \n"
772 " ], \n"
773 " \"actions\": [ \n"
774 " { \n"
775 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
776 " \"redirectUrl\": \"http://bar.com\" \n"
777 " } \n"
778 " ], \n"
779 " \"priority\": 200 \n"
780 "} ";
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_));
792 URLMatcher matcher;
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