Home | History | Annotate | Download | only in declarative_webrequest
      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_condition.h"
      6 
      7 #include <set>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/test/values_test_util.h"
     12 #include "base/values.h"
     13 #include "components/url_matcher/url_matcher_constants.h"
     14 #include "content/public/browser/resource_request_info.h"
     15 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
     16 #include "net/base/request_priority.h"
     17 #include "net/url_request/url_request.h"
     18 #include "net/url_request/url_request_test_util.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 using content::ResourceType;
     22 using url_matcher::URLMatcher;
     23 using url_matcher::URLMatcherConditionSet;
     24 
     25 namespace extensions {
     26 
     27 TEST(WebRequestConditionTest, CreateCondition) {
     28   // Necessary for TestURLRequest.
     29   base::MessageLoopForIO message_loop;
     30   URLMatcher matcher;
     31 
     32   std::string error;
     33   scoped_ptr<WebRequestCondition> result;
     34 
     35   // Test wrong condition name passed.
     36   error.clear();
     37   result = WebRequestCondition::Create(
     38       NULL,
     39       matcher.condition_factory(),
     40       *base::test::ParseJson(
     41            "{ \"invalid\": \"foobar\", \n"
     42            "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
     43            "}"),
     44       &error);
     45   EXPECT_FALSE(error.empty());
     46   EXPECT_FALSE(result.get());
     47 
     48   // Test wrong datatype in host_suffix.
     49   error.clear();
     50   result = WebRequestCondition::Create(
     51       NULL,
     52       matcher.condition_factory(),
     53       *base::test::ParseJson(
     54            "{ \n"
     55            "  \"url\": [], \n"
     56            "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
     57            "}"),
     58       &error);
     59   EXPECT_FALSE(error.empty());
     60   EXPECT_FALSE(result.get());
     61 
     62   // Test success (can we support multiple criteria?)
     63   error.clear();
     64   result = WebRequestCondition::Create(
     65       NULL,
     66       matcher.condition_factory(),
     67       *base::test::ParseJson(
     68            "{ \n"
     69            "  \"resourceType\": [\"main_frame\"], \n"
     70            "  \"url\": { \"hostSuffix\": \"example.com\" }, \n"
     71            "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
     72            "}"),
     73       &error);
     74   EXPECT_EQ("", error);
     75   ASSERT_TRUE(result.get());
     76 
     77   URLMatcherConditionSet::Vector url_matcher_condition_set;
     78   result->GetURLMatcherConditionSets(&url_matcher_condition_set);
     79   matcher.AddConditionSets(url_matcher_condition_set);
     80 
     81   net::TestURLRequestContext context;
     82   const GURL http_url("http://www.example.com");
     83   scoped_ptr<net::URLRequest> match_request(context.CreateRequest(
     84       http_url, net::DEFAULT_PRIORITY, NULL, NULL));
     85   WebRequestData data(match_request.get(), ON_BEFORE_REQUEST);
     86   WebRequestDataWithMatchIds request_data(&data);
     87   request_data.url_match_ids = matcher.MatchURL(http_url);
     88   EXPECT_EQ(1u, request_data.url_match_ids.size());
     89   content::ResourceRequestInfo::AllocateForTesting(
     90       match_request.get(),
     91       content::RESOURCE_TYPE_MAIN_FRAME,
     92       NULL,
     93       -1,
     94       -1,
     95       -1,
     96       false);
     97   EXPECT_TRUE(result->IsFulfilled(request_data));
     98 
     99   const GURL https_url("https://www.example.com");
    100   scoped_ptr<net::URLRequest> wrong_resource_type(context.CreateRequest(
    101       https_url, net::DEFAULT_PRIORITY, NULL, NULL));
    102   data.request = wrong_resource_type.get();
    103   request_data.url_match_ids = matcher.MatchURL(http_url);
    104   // Make sure IsFulfilled does not fail because of URL matching.
    105   EXPECT_EQ(1u, request_data.url_match_ids.size());
    106   content::ResourceRequestInfo::AllocateForTesting(
    107       wrong_resource_type.get(),
    108       content::RESOURCE_TYPE_SUB_FRAME,
    109       NULL,
    110       -1,
    111       -1,
    112       -1,
    113       false);
    114   EXPECT_FALSE(result->IsFulfilled(request_data));
    115 }
    116 
    117 TEST(WebRequestConditionTest, CreateConditionFirstPartyForCookies) {
    118   // Necessary for TestURLRequest.
    119   base::MessageLoopForIO message_loop;
    120   URLMatcher matcher;
    121 
    122   std::string error;
    123   scoped_ptr<WebRequestCondition> result;
    124 
    125   result = WebRequestCondition::Create(
    126       NULL,
    127       matcher.condition_factory(),
    128       *base::test::ParseJson(
    129            "{ \n"
    130            "  \"firstPartyForCookiesUrl\": { \"hostPrefix\": \"fpfc\"}, \n"
    131            "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
    132            "}"),
    133       &error);
    134   EXPECT_EQ("", error);
    135   ASSERT_TRUE(result.get());
    136 
    137   URLMatcherConditionSet::Vector url_matcher_condition_set;
    138   result->GetURLMatcherConditionSets(&url_matcher_condition_set);
    139   matcher.AddConditionSets(url_matcher_condition_set);
    140 
    141   net::TestURLRequestContext context;
    142   const GURL http_url("http://www.example.com");
    143   const GURL first_party_url("http://fpfc.example.com");
    144   scoped_ptr<net::URLRequest> match_request(context.CreateRequest(
    145       http_url, net::DEFAULT_PRIORITY, NULL, NULL));
    146   WebRequestData data(match_request.get(), ON_BEFORE_REQUEST);
    147   WebRequestDataWithMatchIds request_data(&data);
    148   request_data.url_match_ids = matcher.MatchURL(http_url);
    149   EXPECT_EQ(0u, request_data.url_match_ids.size());
    150   request_data.first_party_url_match_ids = matcher.MatchURL(first_party_url);
    151   EXPECT_EQ(1u, request_data.first_party_url_match_ids.size());
    152   content::ResourceRequestInfo::AllocateForTesting(
    153       match_request.get(),
    154       content::RESOURCE_TYPE_MAIN_FRAME,
    155       NULL,
    156       -1,
    157       -1,
    158       -1,
    159       false);
    160   EXPECT_TRUE(result->IsFulfilled(request_data));
    161 }
    162 
    163 // Conditions without UrlFilter attributes need to be independent of URL
    164 // matching results. We test here that:
    165 //   1. A non-empty condition without UrlFilter attributes is fulfilled iff its
    166 //      attributes are fulfilled.
    167 //   2. An empty condition (in particular, without UrlFilter attributes) is
    168 //      always fulfilled.
    169 TEST(WebRequestConditionTest, NoUrlAttributes) {
    170   // Necessary for TestURLRequest.
    171   base::MessageLoopForIO message_loop;
    172   URLMatcher matcher;
    173   std::string error;
    174 
    175   // The empty condition.
    176   error.clear();
    177   scoped_ptr<WebRequestCondition> condition_empty = WebRequestCondition::Create(
    178       NULL,
    179       matcher.condition_factory(),
    180       *base::test::ParseJson(
    181            "{ \n"
    182            "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
    183            "}"),
    184       &error);
    185   EXPECT_EQ("", error);
    186   ASSERT_TRUE(condition_empty.get());
    187 
    188   // A condition without a UrlFilter attribute, which is always true.
    189   error.clear();
    190   scoped_ptr<WebRequestCondition> condition_no_url_true =
    191       WebRequestCondition::Create(
    192           NULL,
    193           matcher.condition_factory(),
    194           *base::test::ParseJson(
    195                "{ \n"
    196                "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
    197                "\n"
    198                // There is no "1st party for cookies" URL in the requests below,
    199                // therefore all requests are considered first party for cookies.
    200                "  \"thirdPartyForCookies\": false, \n"
    201                "}"),
    202           &error);
    203   EXPECT_EQ("", error);
    204   ASSERT_TRUE(condition_no_url_true.get());
    205 
    206   // A condition without a UrlFilter attribute, which is always false.
    207   error.clear();
    208   scoped_ptr<WebRequestCondition> condition_no_url_false =
    209       WebRequestCondition::Create(
    210           NULL,
    211           matcher.condition_factory(),
    212           *base::test::ParseJson(
    213                "{ \n"
    214                "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
    215                "\n"
    216                "  \"thirdPartyForCookies\": true, \n"
    217                "}"),
    218           &error);
    219   EXPECT_EQ("", error);
    220   ASSERT_TRUE(condition_no_url_false.get());
    221 
    222   net::TestURLRequestContext context;
    223   scoped_ptr<net::URLRequest> https_request(context.CreateRequest(
    224       GURL("https://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL));
    225 
    226   // 1. A non-empty condition without UrlFilter attributes is fulfilled iff its
    227   //    attributes are fulfilled.
    228   WebRequestData data(https_request.get(), ON_BEFORE_REQUEST);
    229   EXPECT_FALSE(
    230       condition_no_url_false->IsFulfilled(WebRequestDataWithMatchIds(&data)));
    231 
    232   data = WebRequestData(https_request.get(), ON_BEFORE_REQUEST);
    233   EXPECT_TRUE(
    234       condition_no_url_true->IsFulfilled(WebRequestDataWithMatchIds(&data)));
    235 
    236   // 2. An empty condition (in particular, without UrlFilter attributes) is
    237   //    always fulfilled.
    238   data = WebRequestData(https_request.get(), ON_BEFORE_REQUEST);
    239   EXPECT_TRUE(condition_empty->IsFulfilled(WebRequestDataWithMatchIds(&data)));
    240 }
    241 
    242 TEST(WebRequestConditionTest, CreateConditionSet) {
    243   // Necessary for TestURLRequest.
    244   base::MessageLoopForIO message_loop;
    245   URLMatcher matcher;
    246 
    247   WebRequestConditionSet::AnyVector conditions;
    248   conditions.push_back(linked_ptr<base::Value>(base::test::ParseJson(
    249       "{ \n"
    250       "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
    251       "  \"url\": { \n"
    252       "    \"hostSuffix\": \"example.com\", \n"
    253       "    \"schemes\": [\"http\"], \n"
    254       "  }, \n"
    255       "}").release()));
    256   conditions.push_back(linked_ptr<base::Value>(base::test::ParseJson(
    257       "{ \n"
    258       "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
    259       "  \"url\": { \n"
    260       "    \"hostSuffix\": \"example.com\", \n"
    261       "    \"hostPrefix\": \"www\", \n"
    262       "    \"schemes\": [\"https\"], \n"
    263       "  }, \n"
    264       "}").release()));
    265 
    266   // Test insertion
    267   std::string error;
    268   scoped_ptr<WebRequestConditionSet> result = WebRequestConditionSet::Create(
    269       NULL, matcher.condition_factory(), conditions, &error);
    270   EXPECT_EQ("", error);
    271   ASSERT_TRUE(result.get());
    272   EXPECT_EQ(2u, result->conditions().size());
    273 
    274   // Tell the URLMatcher about our shiny new patterns.
    275   URLMatcherConditionSet::Vector url_matcher_condition_set;
    276   result->GetURLMatcherConditionSets(&url_matcher_condition_set);
    277   matcher.AddConditionSets(url_matcher_condition_set);
    278 
    279   // Test that the result is correct and matches http://www.example.com and
    280   // https://www.example.com
    281   GURL http_url("http://www.example.com");
    282   net::TestURLRequestContext context;
    283   scoped_ptr<net::URLRequest> http_request(context.CreateRequest(
    284       http_url, net::DEFAULT_PRIORITY, NULL, NULL));
    285   WebRequestData data(http_request.get(), ON_BEFORE_REQUEST);
    286   WebRequestDataWithMatchIds request_data(&data);
    287   request_data.url_match_ids = matcher.MatchURL(http_url);
    288   EXPECT_EQ(1u, request_data.url_match_ids.size());
    289   EXPECT_TRUE(result->IsFulfilled(*(request_data.url_match_ids.begin()),
    290                                   request_data));
    291 
    292   GURL https_url("https://www.example.com");
    293   request_data.url_match_ids = matcher.MatchURL(https_url);
    294   EXPECT_EQ(1u, request_data.url_match_ids.size());
    295   scoped_ptr<net::URLRequest> https_request(context.CreateRequest(
    296       https_url, net::DEFAULT_PRIORITY, NULL, NULL));
    297   data.request = https_request.get();
    298   EXPECT_TRUE(result->IsFulfilled(*(request_data.url_match_ids.begin()),
    299                                   request_data));
    300 
    301   // Check that both, hostPrefix and hostSuffix are evaluated.
    302   GURL https_foo_url("https://foo.example.com");
    303   request_data.url_match_ids = matcher.MatchURL(https_foo_url);
    304   EXPECT_EQ(0u, request_data.url_match_ids.size());
    305   scoped_ptr<net::URLRequest> https_foo_request(context.CreateRequest(
    306       https_foo_url, net::DEFAULT_PRIORITY, NULL, NULL));
    307   data.request = https_foo_request.get();
    308   EXPECT_FALSE(result->IsFulfilled(-1, request_data));
    309 }
    310 
    311 TEST(WebRequestConditionTest, TestPortFilter) {
    312   // Necessary for TestURLRequest.
    313   base::MessageLoopForIO message_loop;
    314   URLMatcher matcher;
    315 
    316   WebRequestConditionSet::AnyVector conditions;
    317   conditions.push_back(linked_ptr<base::Value>(base::test::ParseJson(
    318       "{ \n"
    319       "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
    320       "  \"url\": { \n"
    321       "    \"ports\": [80, [1000, 1010]], \n"  // Allow 80;1000-1010.
    322       "    \"hostSuffix\": \"example.com\", \n"
    323       "  }, \n"
    324       "}").release()));
    325 
    326   // Test insertion
    327   std::string error;
    328   scoped_ptr<WebRequestConditionSet> result = WebRequestConditionSet::Create(
    329       NULL, matcher.condition_factory(), conditions, &error);
    330   EXPECT_EQ("", error);
    331   ASSERT_TRUE(result.get());
    332   EXPECT_EQ(1u, result->conditions().size());
    333 
    334   // Tell the URLMatcher about our shiny new patterns.
    335   URLMatcherConditionSet::Vector url_matcher_condition_set;
    336   result->GetURLMatcherConditionSets(&url_matcher_condition_set);
    337   matcher.AddConditionSets(url_matcher_condition_set);
    338 
    339   std::set<URLMatcherConditionSet::ID> url_match_ids;
    340 
    341   // Test various URLs.
    342   GURL http_url("http://www.example.com");
    343   net::TestURLRequestContext context;
    344   scoped_ptr<net::URLRequest> http_request(context.CreateRequest(
    345       http_url, net::DEFAULT_PRIORITY, NULL, NULL));
    346   url_match_ids = matcher.MatchURL(http_url);
    347   ASSERT_EQ(1u, url_match_ids.size());
    348 
    349   GURL http_url_80("http://www.example.com:80");
    350   scoped_ptr<net::URLRequest> http_request_80(context.CreateRequest(
    351       http_url_80, net::DEFAULT_PRIORITY, NULL, NULL));
    352   url_match_ids = matcher.MatchURL(http_url_80);
    353   ASSERT_EQ(1u, url_match_ids.size());
    354 
    355   GURL http_url_1000("http://www.example.com:1000");
    356   scoped_ptr<net::URLRequest> http_request_1000(context.CreateRequest(
    357       http_url_1000, net::DEFAULT_PRIORITY, NULL, NULL));
    358   url_match_ids = matcher.MatchURL(http_url_1000);
    359   ASSERT_EQ(1u, url_match_ids.size());
    360 
    361   GURL http_url_2000("http://www.example.com:2000");
    362   scoped_ptr<net::URLRequest> http_request_2000(context.CreateRequest(
    363       http_url_2000, net::DEFAULT_PRIORITY, NULL, NULL));
    364   url_match_ids = matcher.MatchURL(http_url_2000);
    365   ASSERT_EQ(0u, url_match_ids.size());
    366 }
    367 
    368 // Create a condition with two attributes: one on the request header and one on
    369 // the response header. The Create() method should fail and complain that it is
    370 // impossible that both conditions are fulfilled at the same time.
    371 TEST(WebRequestConditionTest, ConditionsWithConflictingStages) {
    372   // Necessary for TestURLRequest.
    373   base::MessageLoopForIO message_loop;
    374   URLMatcher matcher;
    375 
    376   std::string error;
    377   scoped_ptr<WebRequestCondition> result;
    378 
    379   // Test error on incompatible application stages for involved attributes.
    380   error.clear();
    381   result = WebRequestCondition::Create(
    382       NULL,
    383       matcher.condition_factory(),
    384       *base::test::ParseJson(
    385            "{ \n"
    386            "  \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
    387            // Pass a JS array with one empty object to each of the header
    388            // filters.
    389            "  \"requestHeaders\": [{}], \n"
    390            "  \"responseHeaders\": [{}], \n"
    391            "}"),
    392       &error);
    393   EXPECT_FALSE(error.empty());
    394   EXPECT_FALSE(result.get());
    395 }
    396 
    397 }  // namespace extensions
    398