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