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