Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_webrequest / webrequest_rules_registry_unittest.cc
blob8da1830904a43a8dce5b12bc33417f64fc77aa0c
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 "extensions/browser/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/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/stl_util.h"
16 #include "base/test/values_test_util.h"
17 #include "base/values.h"
18 #include "chrome/common/extensions/extension_test_util.h"
19 #include "components/url_matcher/url_matcher_constants.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "extensions/browser/api/declarative/rules_registry_service.h"
22 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
23 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
24 #include "net/base/request_priority.h"
25 #include "net/url_request/url_request.h"
26 #include "net/url_request/url_request_test_util.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest-message.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 using base::Value;
32 using extension_test_util::LoadManifest;
33 using extension_test_util::LoadManifestUnchecked;
34 using testing::HasSubstr;
35 using url_matcher::URLMatcher;
37 namespace {
38 const char kExtensionId[] = "ext1";
39 const char kExtensionId2[] = "ext2";
40 const char kRuleId1[] = "rule1";
41 const char kRuleId2[] = "rule2";
42 const char kRuleId3[] = "rule3";
43 const char kRuleId4[] = "rule4";
44 } // namespace
46 namespace extensions {
48 namespace helpers = extension_web_request_api_helpers;
49 namespace keys = declarative_webrequest_constants;
50 namespace keys2 = url_matcher::url_matcher_constants;
52 class TestWebRequestRulesRegistry : public WebRequestRulesRegistry {
53 public:
54 explicit TestWebRequestRulesRegistry(
55 scoped_refptr<InfoMap> extension_info_map)
56 : WebRequestRulesRegistry(NULL /*profile*/,
57 NULL /* cache_delegate */,
58 RulesRegistryService::kDefaultRulesRegistryID),
59 num_clear_cache_calls_(0) {
60 SetExtensionInfoMapForTesting(extension_info_map);
63 // Returns how often the in-memory caches of the renderers were instructed
64 // to be cleared.
65 int num_clear_cache_calls() const { return num_clear_cache_calls_; }
67 // How many rules are there which have some conditions not triggered by URL
68 // matches.
69 size_t RulesWithoutTriggers() const {
70 return rules_with_untriggered_conditions_for_test().size();
73 protected:
74 ~TestWebRequestRulesRegistry() override {}
76 void ClearCacheOnNavigation() override { ++num_clear_cache_calls_; }
78 private:
79 int num_clear_cache_calls_;
82 class WebRequestRulesRegistryTest : public testing::Test {
83 public:
84 WebRequestRulesRegistryTest()
85 : ui_(content::BrowserThread::UI, &message_loop_),
86 io_(content::BrowserThread::IO, &message_loop_) {}
88 ~WebRequestRulesRegistryTest() override {}
90 void SetUp() override;
92 void TearDown() override {
93 // Make sure that deletion traits of all registries are executed.
94 message_loop_.RunUntilIdle();
97 // Returns a rule that roughly matches http://*.example.com and
98 // https://www.example.com and cancels it
99 linked_ptr<api::events::Rule> CreateRule1() {
100 base::ListValue* scheme_http = new base::ListValue();
101 scheme_http->Append(new base::StringValue("http"));
102 base::DictionaryValue* http_condition_dict = new base::DictionaryValue();
103 http_condition_dict->Set(keys2::kSchemesKey, scheme_http);
104 http_condition_dict->SetString(keys2::kHostSuffixKey, "example.com");
105 base::DictionaryValue http_condition_url_filter;
106 http_condition_url_filter.Set(keys::kUrlKey, http_condition_dict);
107 http_condition_url_filter.SetString(keys::kInstanceTypeKey,
108 keys::kRequestMatcherType);
110 base::ListValue* scheme_https = new base::ListValue();
111 scheme_http->Append(new base::StringValue("https"));
112 base::DictionaryValue* https_condition_dict = new base::DictionaryValue();
113 https_condition_dict->Set(keys2::kSchemesKey, scheme_https);
114 https_condition_dict->SetString(keys2::kHostSuffixKey, "example.com");
115 https_condition_dict->SetString(keys2::kHostPrefixKey, "www");
116 base::DictionaryValue https_condition_url_filter;
117 https_condition_url_filter.Set(keys::kUrlKey, https_condition_dict);
118 https_condition_url_filter.SetString(keys::kInstanceTypeKey,
119 keys::kRequestMatcherType);
121 base::DictionaryValue action_dict;
122 action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
124 linked_ptr<api::events::Rule> rule(new api::events::Rule);
125 rule->id.reset(new std::string(kRuleId1));
126 rule->priority.reset(new int(100));
127 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy()));
128 rule->conditions.push_back(
129 linked_ptr<base::Value>(http_condition_url_filter.DeepCopy()));
130 rule->conditions.push_back(
131 linked_ptr<base::Value>(https_condition_url_filter.DeepCopy()));
132 return rule;
135 // Returns a rule that matches anything and cancels it.
136 linked_ptr<api::events::Rule> CreateRule2() {
137 base::DictionaryValue condition_dict;
138 condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType);
140 base::DictionaryValue action_dict;
141 action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
143 linked_ptr<api::events::Rule> rule(new api::events::Rule);
144 rule->id.reset(new std::string(kRuleId2));
145 rule->priority.reset(new int(100));
146 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy()));
147 rule->conditions.push_back(
148 linked_ptr<base::Value>(condition_dict.DeepCopy()));
149 return rule;
152 linked_ptr<api::events::Rule> CreateRedirectRule(
153 const std::string& destination) {
154 base::DictionaryValue condition_dict;
155 condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType);
157 base::DictionaryValue action_dict;
158 action_dict.SetString(keys::kInstanceTypeKey, keys::kRedirectRequestType);
159 action_dict.SetString(keys::kRedirectUrlKey, destination);
161 linked_ptr<api::events::Rule> rule(new api::events::Rule);
162 rule->id.reset(new std::string(kRuleId3));
163 rule->priority.reset(new int(100));
164 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy()));
165 rule->conditions.push_back(
166 linked_ptr<base::Value>(condition_dict.DeepCopy()));
167 return rule;
170 // Create a rule to ignore all other rules for a destination that
171 // contains index.html.
172 linked_ptr<api::events::Rule> CreateIgnoreRule() {
173 base::DictionaryValue condition_dict;
174 base::DictionaryValue* http_condition_dict = new base::DictionaryValue();
175 http_condition_dict->SetString(keys2::kPathContainsKey, "index.html");
176 condition_dict.SetString(keys::kInstanceTypeKey, keys::kRequestMatcherType);
177 condition_dict.Set(keys::kUrlKey, http_condition_dict);
179 base::DictionaryValue action_dict;
180 action_dict.SetString(keys::kInstanceTypeKey, keys::kIgnoreRulesType);
181 action_dict.SetInteger(keys::kLowerPriorityThanKey, 150);
183 linked_ptr<api::events::Rule> rule(new api::events::Rule);
184 rule->id.reset(new std::string(kRuleId4));
185 rule->priority.reset(new int(200));
186 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy()));
187 rule->conditions.push_back(
188 linked_ptr<base::Value>(condition_dict.DeepCopy()));
189 return rule;
192 // Create a condition with the attributes specified. An example value of
193 // |attributes| is: "\"resourceType\": [\"stylesheet\"], \n".
194 linked_ptr<base::Value> CreateCondition(const std::string& attributes) {
195 std::string json_description =
196 "{ \n"
197 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n";
198 json_description += attributes;
199 json_description += "}";
201 return linked_ptr<base::Value>(
202 base::test::ParseJson(json_description).release());
205 // Create a rule with the ID |rule_id| and with conditions created from the
206 // |attributes| specified (one entry one condition). An example value of a
207 // string from |attributes| is: "\"resourceType\": [\"stylesheet\"], \n".
208 linked_ptr<api::events::Rule> CreateCancellingRule(
209 const char* rule_id,
210 const std::vector<const std::string*>& attributes) {
211 base::DictionaryValue action_dict;
212 action_dict.SetString(keys::kInstanceTypeKey, keys::kCancelRequestType);
214 linked_ptr<api::events::Rule> rule(new api::events::Rule);
215 rule->id.reset(new std::string(rule_id));
216 rule->priority.reset(new int(1));
217 rule->actions.push_back(linked_ptr<base::Value>(action_dict.DeepCopy()));
218 for (std::vector<const std::string*>::const_iterator it =
219 attributes.begin();
220 it != attributes.end(); ++it)
221 rule->conditions.push_back(CreateCondition(**it));
222 return rule;
225 protected:
226 base::MessageLoopForIO message_loop_;
227 content::TestBrowserThread ui_;
228 content::TestBrowserThread io_;
229 // Two extensions with host permissions for all URLs and the DWR permission.
230 // Installation times will be so that |extension_| is older than
231 // |extension2_|.
232 scoped_refptr<Extension> extension_;
233 scoped_refptr<Extension> extension2_;
234 scoped_refptr<InfoMap> extension_info_map_;
237 void WebRequestRulesRegistryTest::SetUp() {
238 testing::Test::SetUp();
240 std::string error;
241 extension_ = LoadManifestUnchecked("permissions",
242 "web_request_all_host_permissions.json",
243 Manifest::INVALID_LOCATION,
244 Extension::NO_FLAGS,
245 kExtensionId,
246 &error);
247 ASSERT_TRUE(extension_.get()) << error;
248 extension2_ = LoadManifestUnchecked("permissions",
249 "web_request_all_host_permissions.json",
250 Manifest::INVALID_LOCATION,
251 Extension::NO_FLAGS,
252 kExtensionId2,
253 &error);
254 ASSERT_TRUE(extension2_.get()) << error;
255 extension_info_map_ = new InfoMap;
256 ASSERT_TRUE(extension_info_map_.get());
257 extension_info_map_->AddExtension(extension_.get(),
258 base::Time() + base::TimeDelta::FromDays(1),
259 false /*incognito_enabled*/,
260 false /*notifications_disabled*/);
261 extension_info_map_->AddExtension(extension2_.get(),
262 base::Time() + base::TimeDelta::FromDays(2),
263 false /*incognito_enabled*/,
264 false /*notifications_disabled*/);
268 TEST_F(WebRequestRulesRegistryTest, AddRulesImpl) {
269 scoped_refptr<TestWebRequestRulesRegistry> registry(
270 new TestWebRequestRulesRegistry(extension_info_map_));
271 std::string error;
273 std::vector<linked_ptr<api::events::Rule>> rules;
274 rules.push_back(CreateRule1());
275 rules.push_back(CreateRule2());
277 error = registry->AddRules(kExtensionId, rules);
278 EXPECT_EQ("", error);
279 EXPECT_EQ(1, registry->num_clear_cache_calls());
281 std::set<const WebRequestRule*> matches;
283 GURL http_url("http://www.example.com");
284 net::TestURLRequestContext context;
285 scoped_ptr<net::URLRequest> http_request(context.CreateRequest(
286 http_url, net::DEFAULT_PRIORITY, NULL));
287 WebRequestData request_data(http_request.get(), ON_BEFORE_REQUEST);
288 matches = registry->GetMatches(request_data);
289 EXPECT_EQ(2u, matches.size());
291 std::set<WebRequestRule::GlobalRuleId> matches_ids;
292 for (std::set<const WebRequestRule*>::const_iterator it = matches.begin();
293 it != matches.end(); ++it)
294 matches_ids.insert((*it)->id());
295 EXPECT_TRUE(ContainsKey(matches_ids, std::make_pair(kExtensionId, kRuleId1)));
296 EXPECT_TRUE(ContainsKey(matches_ids, std::make_pair(kExtensionId, kRuleId2)));
298 GURL foobar_url("http://www.foobar.com");
299 scoped_ptr<net::URLRequest> foobar_request(context.CreateRequest(
300 foobar_url, net::DEFAULT_PRIORITY, NULL));
301 request_data.request = foobar_request.get();
302 matches = registry->GetMatches(request_data);
303 EXPECT_EQ(1u, matches.size());
304 WebRequestRule::GlobalRuleId expected_pair =
305 std::make_pair(kExtensionId, kRuleId2);
306 EXPECT_EQ(expected_pair, (*matches.begin())->id());
309 TEST_F(WebRequestRulesRegistryTest, RemoveRulesImpl) {
310 scoped_refptr<TestWebRequestRulesRegistry> registry(
311 new TestWebRequestRulesRegistry(extension_info_map_));
312 std::string error;
314 // Setup RulesRegistry to contain two rules.
315 std::vector<linked_ptr<api::events::Rule>> rules_to_add;
316 rules_to_add.push_back(CreateRule1());
317 rules_to_add.push_back(CreateRule2());
318 error = registry->AddRules(kExtensionId, rules_to_add);
319 EXPECT_EQ("", error);
320 EXPECT_EQ(1, registry->num_clear_cache_calls());
322 // Verify initial state.
323 std::vector<linked_ptr<api::events::Rule>> registered_rules;
324 registry->GetAllRules(kExtensionId, &registered_rules);
325 EXPECT_EQ(2u, registered_rules.size());
326 EXPECT_EQ(1u, registry->RulesWithoutTriggers());
328 // Remove first rule.
329 std::vector<std::string> rules_to_remove;
330 rules_to_remove.push_back(kRuleId1);
331 error = registry->RemoveRules(kExtensionId, rules_to_remove);
332 EXPECT_EQ("", error);
333 EXPECT_EQ(2, registry->num_clear_cache_calls());
335 // Verify that only one rule is left.
336 registered_rules.clear();
337 registry->GetAllRules(kExtensionId, &registered_rules);
338 EXPECT_EQ(1u, registered_rules.size());
339 EXPECT_EQ(1u, registry->RulesWithoutTriggers());
341 // Now rules_to_remove contains both rules, i.e. one that does not exist in
342 // the rules registry anymore. Effectively we only remove the second rule.
343 rules_to_remove.push_back(kRuleId2);
344 error = registry->RemoveRules(kExtensionId, rules_to_remove);
345 EXPECT_EQ("", error);
346 EXPECT_EQ(3, registry->num_clear_cache_calls());
348 // Verify that everything is gone.
349 registered_rules.clear();
350 registry->GetAllRules(kExtensionId, &registered_rules);
351 EXPECT_EQ(0u, registered_rules.size());
352 EXPECT_EQ(0u, registry->RulesWithoutTriggers());
354 EXPECT_TRUE(registry->IsEmpty());
357 TEST_F(WebRequestRulesRegistryTest, RemoveAllRulesImpl) {
358 scoped_refptr<TestWebRequestRulesRegistry> registry(
359 new TestWebRequestRulesRegistry(extension_info_map_));
360 std::string error;
362 // Setup RulesRegistry to contain two rules, one for each extension.
363 std::vector<linked_ptr<api::events::Rule>> rules_to_add(1);
364 rules_to_add[0] = CreateRule1();
365 error = registry->AddRules(kExtensionId, rules_to_add);
366 EXPECT_EQ("", error);
367 EXPECT_EQ(1, registry->num_clear_cache_calls());
369 rules_to_add[0] = CreateRule2();
370 error = registry->AddRules(kExtensionId2, rules_to_add);
371 EXPECT_EQ("", error);
372 EXPECT_EQ(2, registry->num_clear_cache_calls());
374 // Verify initial state.
375 std::vector<linked_ptr<api::events::Rule>> registered_rules;
376 registry->GetAllRules(kExtensionId, &registered_rules);
377 EXPECT_EQ(1u, registered_rules.size());
378 registered_rules.clear();
379 registry->GetAllRules(kExtensionId2, &registered_rules);
380 EXPECT_EQ(1u, registered_rules.size());
382 // Remove rule of first extension.
383 error = registry->RemoveAllRules(kExtensionId);
384 EXPECT_EQ("", error);
385 EXPECT_EQ(3, registry->num_clear_cache_calls());
387 // Verify that only the first rule is deleted.
388 registered_rules.clear();
389 registry->GetAllRules(kExtensionId, &registered_rules);
390 EXPECT_EQ(0u, registered_rules.size());
391 registered_rules.clear();
392 registry->GetAllRules(kExtensionId2, &registered_rules);
393 EXPECT_EQ(1u, registered_rules.size());
395 // Test removing rules if none exist.
396 error = registry->RemoveAllRules(kExtensionId);
397 EXPECT_EQ("", error);
398 EXPECT_EQ(4, registry->num_clear_cache_calls());
400 // Remove rule from second extension.
401 error = registry->RemoveAllRules(kExtensionId2);
402 EXPECT_EQ("", error);
403 EXPECT_EQ(5, registry->num_clear_cache_calls());
405 EXPECT_TRUE(registry->IsEmpty());
408 // Test precedences between extensions.
409 TEST_F(WebRequestRulesRegistryTest, Precedences) {
410 scoped_refptr<WebRequestRulesRegistry> registry(
411 new TestWebRequestRulesRegistry(extension_info_map_));
412 std::string error;
414 std::vector<linked_ptr<api::events::Rule>> rules_to_add_1(1);
415 rules_to_add_1[0] = CreateRedirectRule("http://www.foo.com");
416 error = registry->AddRules(kExtensionId, rules_to_add_1);
417 EXPECT_EQ("", error);
419 std::vector<linked_ptr<api::events::Rule>> rules_to_add_2(1);
420 rules_to_add_2[0] = CreateRedirectRule("http://www.bar.com");
421 error = registry->AddRules(kExtensionId2, rules_to_add_2);
422 EXPECT_EQ("", error);
424 GURL url("http://www.google.com");
425 net::TestURLRequestContext context;
426 scoped_ptr<net::URLRequest> request(context.CreateRequest(
427 url, net::DEFAULT_PRIORITY, NULL));
428 WebRequestData request_data(request.get(), ON_BEFORE_REQUEST);
429 std::list<LinkedPtrEventResponseDelta> deltas =
430 registry->CreateDeltas(NULL, request_data, false);
432 // The second extension is installed later and will win for this reason
433 // in conflict resolution.
434 ASSERT_EQ(2u, deltas.size());
435 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
437 std::list<LinkedPtrEventResponseDelta>::iterator i = deltas.begin();
438 LinkedPtrEventResponseDelta winner = *i++;
439 LinkedPtrEventResponseDelta loser = *i;
441 EXPECT_EQ(kExtensionId2, winner->extension_id);
442 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(2),
443 winner->extension_install_time);
444 EXPECT_EQ(GURL("http://www.bar.com"), winner->new_url);
446 EXPECT_EQ(kExtensionId, loser->extension_id);
447 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(1),
448 loser->extension_install_time);
449 EXPECT_EQ(GURL("http://www.foo.com"), loser->new_url);
452 // Test priorities of rules within one extension.
453 TEST_F(WebRequestRulesRegistryTest, Priorities) {
454 scoped_refptr<WebRequestRulesRegistry> registry(
455 new TestWebRequestRulesRegistry(extension_info_map_));
456 std::string error;
458 std::vector<linked_ptr<api::events::Rule>> rules_to_add_1(1);
459 rules_to_add_1[0] = CreateRedirectRule("http://www.foo.com");
460 error = registry->AddRules(kExtensionId, rules_to_add_1);
461 EXPECT_EQ("", error);
463 std::vector<linked_ptr<api::events::Rule>> rules_to_add_2(1);
464 rules_to_add_2[0] = CreateRedirectRule("http://www.bar.com");
465 error = registry->AddRules(kExtensionId2, rules_to_add_2);
466 EXPECT_EQ("", error);
468 std::vector<linked_ptr<api::events::Rule>> rules_to_add_3(1);
469 rules_to_add_3[0] = CreateIgnoreRule();
470 error = registry->AddRules(kExtensionId, rules_to_add_3);
471 EXPECT_EQ("", error);
473 GURL url("http://www.google.com/index.html");
474 net::TestURLRequestContext context;
475 scoped_ptr<net::URLRequest> request(context.CreateRequest(
476 url, net::DEFAULT_PRIORITY, NULL));
477 WebRequestData request_data(request.get(), ON_BEFORE_REQUEST);
478 std::list<LinkedPtrEventResponseDelta> deltas =
479 registry->CreateDeltas(NULL, request_data, false);
481 // The redirect by the first extension is ignored due to the ignore rule.
482 ASSERT_EQ(1u, deltas.size());
483 LinkedPtrEventResponseDelta effective_rule = *(deltas.begin());
485 EXPECT_EQ(kExtensionId2, effective_rule->extension_id);
486 EXPECT_EQ(base::Time() + base::TimeDelta::FromDays(2),
487 effective_rule->extension_install_time);
488 EXPECT_EQ(GURL("http://www.bar.com"), effective_rule->new_url);
491 // Test ignoring of rules by tag.
492 TEST_F(WebRequestRulesRegistryTest, IgnoreRulesByTag) {
493 const char kRule1[] =
494 "{ \n"
495 " \"id\": \"rule1\", \n"
496 " \"tags\": [\"non_matching_tag\", \"ignore_tag\"], \n"
497 " \"conditions\": [ \n"
498 " { \n"
499 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
500 " \"url\": {\"hostSuffix\": \"foo.com\"} \n"
501 " } \n"
502 " ], \n"
503 " \"actions\": [ \n"
504 " { \n"
505 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
506 " \"redirectUrl\": \"http://bar.com\" \n"
507 " } \n"
508 " ], \n"
509 " \"priority\": 200 \n"
510 "} ";
512 const char kRule2[] =
513 "{ \n"
514 " \"id\": \"rule2\", \n"
515 " \"conditions\": [ \n"
516 " { \n"
517 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
518 " \"url\": {\"pathPrefix\": \"/test\"} \n"
519 " } \n"
520 " ], \n"
521 " \"actions\": [ \n"
522 " { \n"
523 " \"instanceType\": \"declarativeWebRequest.IgnoreRules\", \n"
524 " \"hasTag\": \"ignore_tag\" \n"
525 " } \n"
526 " ], \n"
527 " \"priority\": 300 \n"
528 "} ";
530 scoped_ptr<base::Value> value1 = base::JSONReader::Read(kRule1);
531 ASSERT_TRUE(value1.get());
532 scoped_ptr<base::Value> value2 = base::JSONReader::Read(kRule2);
533 ASSERT_TRUE(value2.get());
535 std::vector<linked_ptr<api::events::Rule>> rules;
536 rules.push_back(make_linked_ptr(new api::events::Rule));
537 rules.push_back(make_linked_ptr(new api::events::Rule));
538 ASSERT_TRUE(api::events::Rule::Populate(*value1, rules[0].get()));
539 ASSERT_TRUE(api::events::Rule::Populate(*value2, rules[1].get()));
541 scoped_refptr<WebRequestRulesRegistry> registry(
542 new TestWebRequestRulesRegistry(extension_info_map_));
543 std::string error = registry->AddRulesImpl(kExtensionId, rules);
544 EXPECT_EQ("", error);
545 EXPECT_FALSE(registry->IsEmpty());
547 GURL url("http://www.foo.com/test");
548 net::TestURLRequestContext context;
549 scoped_ptr<net::URLRequest> request(context.CreateRequest(
550 url, net::DEFAULT_PRIORITY, NULL));
551 WebRequestData request_data(request.get(), ON_BEFORE_REQUEST);
552 std::list<LinkedPtrEventResponseDelta> deltas =
553 registry->CreateDeltas(NULL, request_data, false);
555 // The redirect by the redirect rule is ignored due to the ignore rule.
556 std::set<const WebRequestRule*> matches = registry->GetMatches(request_data);
557 EXPECT_EQ(2u, matches.size());
558 ASSERT_EQ(0u, deltas.size());
561 // Test that rules failing IsFulfilled on their conditions are never returned by
562 // GetMatches.
563 TEST_F(WebRequestRulesRegistryTest, GetMatchesCheckFulfilled) {
564 scoped_refptr<TestWebRequestRulesRegistry> registry(
565 new TestWebRequestRulesRegistry(extension_info_map_));
566 const std::string kMatchingUrlAttribute(
567 "\"url\": { \"pathContains\": \"\" }, \n");
568 const std::string kNonMatchingNonUrlAttribute(
569 "\"resourceType\": [\"stylesheet\"], \n");
570 const std::string kBothAttributes(kMatchingUrlAttribute +
571 kNonMatchingNonUrlAttribute);
572 std::string error;
573 std::vector<const std::string*> attributes;
574 std::vector<linked_ptr<api::events::Rule>> rules;
576 // Rules 1 and 2 have one condition, neither of them should fire.
577 attributes.push_back(&kNonMatchingNonUrlAttribute);
578 rules.push_back(CreateCancellingRule(kRuleId1, attributes));
580 attributes.clear();
581 attributes.push_back(&kBothAttributes);
582 rules.push_back(CreateCancellingRule(kRuleId2, attributes));
584 // Rule 3 has two conditions, one with a matching URL attribute, and one
585 // with a non-matching non-URL attribute.
586 attributes.clear();
587 attributes.push_back(&kMatchingUrlAttribute);
588 attributes.push_back(&kNonMatchingNonUrlAttribute);
589 rules.push_back(CreateCancellingRule(kRuleId3, attributes));
591 error = registry->AddRules(kExtensionId, rules);
592 EXPECT_EQ("", error);
593 EXPECT_EQ(1, registry->num_clear_cache_calls());
595 std::set<const WebRequestRule*> matches;
597 GURL http_url("http://www.example.com");
598 net::TestURLRequestContext context;
599 scoped_ptr<net::URLRequest> http_request(context.CreateRequest(
600 http_url, net::DEFAULT_PRIORITY, NULL));
601 WebRequestData request_data(http_request.get(), ON_BEFORE_REQUEST);
602 matches = registry->GetMatches(request_data);
603 EXPECT_EQ(1u, matches.size());
604 WebRequestRule::GlobalRuleId expected_pair = std::make_pair(kExtensionId,
605 kRuleId3);
606 EXPECT_EQ(expected_pair, (*matches.begin())->id());
609 // Test that the url and firstPartyForCookiesUrl attributes are evaluated
610 // against corresponding URLs. Tested on requests where these URLs actually
611 // differ.
612 TEST_F(WebRequestRulesRegistryTest, GetMatchesDifferentUrls) {
613 scoped_refptr<TestWebRequestRulesRegistry> registry(
614 new TestWebRequestRulesRegistry(extension_info_map_));
615 const std::string kUrlAttribute(
616 "\"url\": { \"hostContains\": \"url\" }, \n");
617 const std::string kFirstPartyUrlAttribute(
618 "\"firstPartyForCookiesUrl\": { \"hostContains\": \"fpfc\" }, \n");
619 std::string error;
620 std::vector<const std::string*> attributes;
621 std::vector<linked_ptr<api::events::Rule>> rules;
623 // Rule 1 has one condition, with a url attribute
624 attributes.push_back(&kUrlAttribute);
625 rules.push_back(CreateCancellingRule(kRuleId1, attributes));
627 // Rule 2 has one condition, with a firstPartyForCookiesUrl attribute
628 attributes.clear();
629 attributes.push_back(&kFirstPartyUrlAttribute);
630 rules.push_back(CreateCancellingRule(kRuleId2, attributes));
632 error = registry->AddRules(kExtensionId, rules);
633 EXPECT_EQ("", error);
634 EXPECT_EQ(1, registry->num_clear_cache_calls());
636 std::set<const WebRequestRule*> matches;
638 const GURL urls[] = {
639 GURL("http://url.example.com"), // matching
640 GURL("http://www.example.com") // non-matching
642 const GURL firstPartyUrls[] = {
643 GURL("http://www.example.com"), // non-matching
644 GURL("http://fpfc.example.com") // matching
646 // Which rules should match in subsequent test iterations.
647 const char* const matchingRuleIds[] = { kRuleId1, kRuleId2 };
648 static_assert(arraysize(urls) == arraysize(firstPartyUrls),
649 "urls and firstPartyUrls must have the same number "
650 "of elements");
651 static_assert(arraysize(urls) == arraysize(matchingRuleIds),
652 "urls and matchingRuleIds must have the same number "
653 "of elements");
654 net::TestURLRequestContext context;
656 for (size_t i = 0; i < arraysize(matchingRuleIds); ++i) {
657 // Construct the inputs.
658 scoped_ptr<net::URLRequest> http_request(context.CreateRequest(
659 urls[i], net::DEFAULT_PRIORITY, NULL));
660 WebRequestData request_data(http_request.get(), ON_BEFORE_REQUEST);
661 http_request->set_first_party_for_cookies(firstPartyUrls[i]);
662 // Now run both rules on the input.
663 matches = registry->GetMatches(request_data);
664 SCOPED_TRACE(testing::Message("i = ") << i << ", rule id = "
665 << matchingRuleIds[i]);
666 // Make sure that the right rule succeeded.
667 EXPECT_EQ(1u, matches.size());
668 EXPECT_EQ(WebRequestRule::GlobalRuleId(std::make_pair(kExtensionId,
669 matchingRuleIds[i])),
670 (*matches.begin())->id());
674 TEST(WebRequestRulesRegistrySimpleTest, StageChecker) {
675 // The contentType condition can only be evaluated during ON_HEADERS_RECEIVED
676 // but the SetRequestHeader action can only be executed during
677 // ON_BEFORE_SEND_HEADERS.
678 // Therefore, this is an inconsistent rule that needs to be flagged.
679 const char kRule[] =
680 "{ \n"
681 " \"id\": \"rule1\", \n"
682 " \"conditions\": [ \n"
683 " { \n"
684 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
685 " \"url\": {\"hostSuffix\": \"foo.com\"}, \n"
686 " \"contentType\": [\"image/jpeg\"] \n"
687 " } \n"
688 " ], \n"
689 " \"actions\": [ \n"
690 " { \n"
691 " \"instanceType\": \"declarativeWebRequest.SetRequestHeader\",\n"
692 " \"name\": \"Content-Type\", \n"
693 " \"value\": \"text/plain\" \n"
694 " } \n"
695 " ], \n"
696 " \"priority\": 200 \n"
697 "} ";
699 scoped_ptr<base::Value> value = base::JSONReader::Read(kRule);
700 ASSERT_TRUE(value);
702 api::events::Rule rule;
703 ASSERT_TRUE(api::events::Rule::Populate(*value, &rule));
705 std::string error;
706 URLMatcher matcher;
707 scoped_ptr<WebRequestConditionSet> conditions =
708 WebRequestConditionSet::Create(
709 NULL, matcher.condition_factory(), rule.conditions, &error);
710 ASSERT_TRUE(error.empty()) << error;
711 ASSERT_TRUE(conditions);
713 bool bad_message = false;
714 scoped_ptr<WebRequestActionSet> actions =
715 WebRequestActionSet::Create(
716 NULL, NULL, rule.actions, &error, &bad_message);
717 ASSERT_TRUE(error.empty()) << error;
718 ASSERT_FALSE(bad_message);
719 ASSERT_TRUE(actions);
721 EXPECT_FALSE(WebRequestRulesRegistry::StageChecker(
722 conditions.get(), actions.get(), &error));
723 EXPECT_THAT(error, HasSubstr("no time in the request life-cycle"));
724 EXPECT_THAT(error, HasSubstr(actions->actions().back()->GetName()));
727 TEST(WebRequestRulesRegistrySimpleTest, HostPermissionsChecker) {
728 const char kAction[] = // This action requires all URLs host permission.
729 "{ \n"
730 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
731 " \"redirectUrl\": \"http://bar.com\" \n"
732 "} ";
733 scoped_ptr<base::Value> action_value = base::JSONReader::Read(kAction);
734 ASSERT_TRUE(action_value);
736 WebRequestActionSet::Values actions;
737 actions.push_back(linked_ptr<base::Value>(action_value.release()));
738 ASSERT_TRUE(actions.back().get());
740 std::string error;
741 bool bad_message = false;
742 scoped_ptr<WebRequestActionSet> action_set(
743 WebRequestActionSet::Create(NULL, NULL, actions, &error, &bad_message));
744 ASSERT_TRUE(error.empty()) << error;
745 ASSERT_FALSE(bad_message);
746 ASSERT_TRUE(action_set);
748 scoped_refptr<Extension> extension_no_url(
749 LoadManifest("permissions", "web_request_no_host.json"));
750 scoped_refptr<Extension> extension_some_urls(
751 LoadManifest("permissions", "web_request_com_host_permissions.json"));
752 scoped_refptr<Extension> extension_all_urls(
753 LoadManifest("permissions", "web_request_all_host_permissions.json"));
755 EXPECT_TRUE(WebRequestRulesRegistry::HostPermissionsChecker(
756 extension_all_urls.get(), action_set.get(), &error));
757 EXPECT_TRUE(error.empty()) << error;
759 EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker(
760 extension_some_urls.get(), action_set.get(), &error));
761 EXPECT_THAT(error, HasSubstr("permission for all"));
762 EXPECT_THAT(error, HasSubstr(action_set->actions().back()->GetName()));
764 EXPECT_FALSE(WebRequestRulesRegistry::HostPermissionsChecker(
765 extension_no_url.get(), action_set.get(), &error));
766 EXPECT_THAT(error, HasSubstr("permission for all"));
767 EXPECT_THAT(error, HasSubstr(action_set->actions().back()->GetName()));
770 TEST_F(WebRequestRulesRegistryTest, CheckOriginAndPathRegEx) {
771 const char kRule[] =
772 "{ \n"
773 " \"id\": \"rule1\", \n"
774 " \"conditions\": [ \n"
775 " { \n"
776 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
777 " \"url\": {\"originAndPathMatches\": \"fo+.com\"} \n"
778 " } \n"
779 " ], \n"
780 " \"actions\": [ \n"
781 " { \n"
782 " \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
783 " \"redirectUrl\": \"http://bar.com\" \n"
784 " } \n"
785 " ], \n"
786 " \"priority\": 200 \n"
787 "} ";
789 scoped_ptr<base::Value> value = base::JSONReader::Read(kRule);
790 ASSERT_TRUE(value.get());
792 std::vector<linked_ptr<api::events::Rule>> rules;
793 rules.push_back(make_linked_ptr(new api::events::Rule));
794 ASSERT_TRUE(api::events::Rule::Populate(*value, rules.back().get()));
796 scoped_refptr<WebRequestRulesRegistry> registry(
797 new TestWebRequestRulesRegistry(extension_info_map_));
799 URLMatcher matcher;
800 std::string error = registry->AddRulesImpl(kExtensionId, rules);
801 EXPECT_EQ("", error);
803 net::TestURLRequestContext context;
804 std::list<LinkedPtrEventResponseDelta> deltas;
806 // No match because match is in the query parameter.
807 GURL url1("http://bar.com/index.html?foo.com");
808 scoped_ptr<net::URLRequest> request1(context.CreateRequest(
809 url1, net::DEFAULT_PRIORITY, NULL));
810 WebRequestData request_data1(request1.get(), ON_BEFORE_REQUEST);
811 deltas = registry->CreateDeltas(NULL, request_data1, false);
812 EXPECT_EQ(0u, deltas.size());
814 // This is a correct match.
815 GURL url2("http://foo.com/index.html");
816 scoped_ptr<net::URLRequest> request2(context.CreateRequest(
817 url2, net::DEFAULT_PRIORITY, NULL));
818 WebRequestData request_data2(request2.get(), ON_BEFORE_REQUEST);
819 deltas = registry->CreateDeltas(NULL, request_data2, false);
820 EXPECT_EQ(1u, deltas.size());
823 } // namespace extensions