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