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