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