| OLD | NEW |
| (Empty) |
| 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_condit
ion_attribute.h" | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "base/files/file_path.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/message_loop/message_loop.h" | |
| 11 #include "base/values.h" | |
| 12 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condit
ion.h" | |
| 13 #include "content/public/browser/resource_request_info.h" | |
| 14 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" | |
| 15 #include "net/base/request_priority.h" | |
| 16 #include "net/test/embedded_test_server/embedded_test_server.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 base::DictionaryValue; | |
| 22 using base::FundamentalValue; | |
| 23 using base::ListValue; | |
| 24 using base::StringValue; | |
| 25 using base::Value; | |
| 26 using content::ResourceType; | |
| 27 | |
| 28 namespace extensions { | |
| 29 | |
| 30 namespace keys = declarative_webrequest_constants; | |
| 31 | |
| 32 namespace { | |
| 33 const char kUnknownConditionName[] = "unknownType"; | |
| 34 | |
| 35 base::FilePath TestDataPath(base::StringPiece relative_to_src) { | |
| 36 base::FilePath src_dir; | |
| 37 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); | |
| 38 return src_dir.AppendASCII(relative_to_src); | |
| 39 } | |
| 40 | |
| 41 TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) { | |
| 42 // Necessary for TestURLRequest. | |
| 43 base::MessageLoopForIO message_loop; | |
| 44 | |
| 45 std::string error; | |
| 46 scoped_refptr<const WebRequestConditionAttribute> result; | |
| 47 base::StringValue string_value("main_frame"); | |
| 48 base::ListValue resource_types; | |
| 49 resource_types.Append(new base::StringValue("main_frame")); | |
| 50 | |
| 51 // Test wrong condition name passed. | |
| 52 error.clear(); | |
| 53 result = WebRequestConditionAttribute::Create( | |
| 54 kUnknownConditionName, &resource_types, &error); | |
| 55 EXPECT_FALSE(error.empty()); | |
| 56 EXPECT_FALSE(result.get()); | |
| 57 | |
| 58 // Test wrong data type passed | |
| 59 error.clear(); | |
| 60 result = WebRequestConditionAttribute::Create( | |
| 61 keys::kResourceTypeKey, &string_value, &error); | |
| 62 EXPECT_FALSE(error.empty()); | |
| 63 EXPECT_FALSE(result.get()); | |
| 64 | |
| 65 error.clear(); | |
| 66 result = WebRequestConditionAttribute::Create( | |
| 67 keys::kContentTypeKey, &string_value, &error); | |
| 68 EXPECT_FALSE(error.empty()); | |
| 69 EXPECT_FALSE(result.get()); | |
| 70 | |
| 71 // Test success | |
| 72 error.clear(); | |
| 73 result = WebRequestConditionAttribute::Create( | |
| 74 keys::kResourceTypeKey, &resource_types, &error); | |
| 75 EXPECT_EQ("", error); | |
| 76 ASSERT_TRUE(result.get()); | |
| 77 EXPECT_EQ(WebRequestConditionAttribute::CONDITION_RESOURCE_TYPE, | |
| 78 result->GetType()); | |
| 79 EXPECT_EQ(std::string(keys::kResourceTypeKey), result->GetName()); | |
| 80 } | |
| 81 | |
| 82 TEST(WebRequestConditionAttributeTest, ResourceType) { | |
| 83 // Necessary for TestURLRequest. | |
| 84 base::MessageLoopForIO message_loop; | |
| 85 | |
| 86 std::string error; | |
| 87 base::ListValue resource_types; | |
| 88 // The 'sub_frame' value is chosen arbitrarily, so as the corresponding | |
| 89 // content::ResourceType is not 0, the default value. | |
| 90 resource_types.Append(new base::StringValue("sub_frame")); | |
| 91 | |
| 92 scoped_refptr<const WebRequestConditionAttribute> attribute = | |
| 93 WebRequestConditionAttribute::Create( | |
| 94 keys::kResourceTypeKey, &resource_types, &error); | |
| 95 EXPECT_EQ("", error); | |
| 96 ASSERT_TRUE(attribute.get()); | |
| 97 EXPECT_EQ(std::string(keys::kResourceTypeKey), attribute->GetName()); | |
| 98 | |
| 99 net::TestURLRequestContext context; | |
| 100 scoped_ptr<net::URLRequest> url_request_ok(context.CreateRequest( | |
| 101 GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL)); | |
| 102 content::ResourceRequestInfo::AllocateForTesting( | |
| 103 url_request_ok.get(), | |
| 104 content::RESOURCE_TYPE_SUB_FRAME, | |
| 105 NULL, | |
| 106 -1, | |
| 107 -1, | |
| 108 -1, | |
| 109 false); | |
| 110 EXPECT_TRUE(attribute->IsFulfilled(WebRequestData(url_request_ok.get(), | |
| 111 ON_BEFORE_REQUEST))); | |
| 112 | |
| 113 scoped_ptr<net::URLRequest> url_request_fail(context.CreateRequest( | |
| 114 GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL)); | |
| 115 content::ResourceRequestInfo::AllocateForTesting( | |
| 116 url_request_fail.get(), | |
| 117 content::RESOURCE_TYPE_MAIN_FRAME, | |
| 118 NULL, | |
| 119 -1, | |
| 120 -1, | |
| 121 -1, | |
| 122 false); | |
| 123 EXPECT_FALSE(attribute->IsFulfilled(WebRequestData(url_request_fail.get(), | |
| 124 ON_BEFORE_REQUEST))); | |
| 125 } | |
| 126 | |
| 127 TEST(WebRequestConditionAttributeTest, ContentType) { | |
| 128 // Necessary for TestURLRequest. | |
| 129 base::MessageLoopForIO message_loop; | |
| 130 | |
| 131 std::string error; | |
| 132 scoped_refptr<const WebRequestConditionAttribute> result; | |
| 133 | |
| 134 net::test_server::EmbeddedTestServer test_server; | |
| 135 test_server.ServeFilesFromDirectory(TestDataPath( | |
| 136 "chrome/test/data/extensions/api_test/webrequest/declarative")); | |
| 137 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady()); | |
| 138 | |
| 139 net::TestURLRequestContext context; | |
| 140 net::TestDelegate delegate; | |
| 141 scoped_ptr<net::URLRequest> url_request( | |
| 142 context.CreateRequest(test_server.GetURL("/headers.html"), | |
| 143 net::DEFAULT_PRIORITY, | |
| 144 &delegate, | |
| 145 NULL)); | |
| 146 url_request->Start(); | |
| 147 base::MessageLoop::current()->Run(); | |
| 148 | |
| 149 base::ListValue content_types; | |
| 150 content_types.Append(new base::StringValue("text/plain")); | |
| 151 scoped_refptr<const WebRequestConditionAttribute> attribute_include = | |
| 152 WebRequestConditionAttribute::Create( | |
| 153 keys::kContentTypeKey, &content_types, &error); | |
| 154 EXPECT_EQ("", error); | |
| 155 ASSERT_TRUE(attribute_include.get()); | |
| 156 EXPECT_FALSE(attribute_include->IsFulfilled( | |
| 157 WebRequestData(url_request.get(), ON_BEFORE_REQUEST, | |
| 158 url_request->response_headers()))); | |
| 159 EXPECT_TRUE(attribute_include->IsFulfilled( | |
| 160 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, | |
| 161 url_request->response_headers()))); | |
| 162 EXPECT_EQ(std::string(keys::kContentTypeKey), attribute_include->GetName()); | |
| 163 | |
| 164 scoped_refptr<const WebRequestConditionAttribute> attribute_exclude = | |
| 165 WebRequestConditionAttribute::Create( | |
| 166 keys::kExcludeContentTypeKey, &content_types, &error); | |
| 167 EXPECT_EQ("", error); | |
| 168 ASSERT_TRUE(attribute_exclude.get()); | |
| 169 EXPECT_FALSE(attribute_exclude->IsFulfilled( | |
| 170 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, | |
| 171 url_request->response_headers()))); | |
| 172 | |
| 173 content_types.Clear(); | |
| 174 content_types.Append(new base::StringValue("something/invalid")); | |
| 175 scoped_refptr<const WebRequestConditionAttribute> attribute_unincluded = | |
| 176 WebRequestConditionAttribute::Create( | |
| 177 keys::kContentTypeKey, &content_types, &error); | |
| 178 EXPECT_EQ("", error); | |
| 179 ASSERT_TRUE(attribute_unincluded.get()); | |
| 180 EXPECT_FALSE(attribute_unincluded->IsFulfilled( | |
| 181 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, | |
| 182 url_request->response_headers()))); | |
| 183 | |
| 184 scoped_refptr<const WebRequestConditionAttribute> attribute_unexcluded = | |
| 185 WebRequestConditionAttribute::Create( | |
| 186 keys::kExcludeContentTypeKey, &content_types, &error); | |
| 187 EXPECT_EQ("", error); | |
| 188 ASSERT_TRUE(attribute_unexcluded.get()); | |
| 189 EXPECT_TRUE(attribute_unexcluded->IsFulfilled( | |
| 190 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED, | |
| 191 url_request->response_headers()))); | |
| 192 EXPECT_EQ(std::string(keys::kExcludeContentTypeKey), | |
| 193 attribute_unexcluded->GetName()); | |
| 194 } | |
| 195 | |
| 196 // Testing WebRequestConditionAttributeThirdParty. | |
| 197 TEST(WebRequestConditionAttributeTest, ThirdParty) { | |
| 198 // Necessary for TestURLRequest. | |
| 199 base::MessageLoopForIO message_loop; | |
| 200 | |
| 201 std::string error; | |
| 202 const FundamentalValue value_true(true); | |
| 203 // This attribute matches only third party requests. | |
| 204 scoped_refptr<const WebRequestConditionAttribute> third_party_attribute = | |
| 205 WebRequestConditionAttribute::Create(keys::kThirdPartyKey, | |
| 206 &value_true, | |
| 207 &error); | |
| 208 ASSERT_EQ("", error); | |
| 209 ASSERT_TRUE(third_party_attribute.get()); | |
| 210 EXPECT_EQ(std::string(keys::kThirdPartyKey), | |
| 211 third_party_attribute->GetName()); | |
| 212 const FundamentalValue value_false(false); | |
| 213 // This attribute matches only first party requests. | |
| 214 scoped_refptr<const WebRequestConditionAttribute> first_party_attribute = | |
| 215 WebRequestConditionAttribute::Create(keys::kThirdPartyKey, | |
| 216 &value_false, | |
| 217 &error); | |
| 218 ASSERT_EQ("", error); | |
| 219 ASSERT_TRUE(first_party_attribute.get()); | |
| 220 EXPECT_EQ(std::string(keys::kThirdPartyKey), | |
| 221 first_party_attribute->GetName()); | |
| 222 | |
| 223 const GURL url_empty; | |
| 224 const GURL url_a("http://a.com"); | |
| 225 const GURL url_b("http://b.com"); | |
| 226 net::TestURLRequestContext context; | |
| 227 net::TestDelegate delegate; | |
| 228 scoped_ptr<net::URLRequest> url_request( | |
| 229 context.CreateRequest(url_a, net::DEFAULT_PRIORITY, &delegate, NULL)); | |
| 230 | |
| 231 for (unsigned int i = 1; i <= kLastActiveStage; i <<= 1) { | |
| 232 if (!(kActiveStages & i)) | |
| 233 continue; | |
| 234 const RequestStage stage = static_cast<RequestStage>(i); | |
| 235 url_request->set_first_party_for_cookies(url_empty); | |
| 236 EXPECT_FALSE(third_party_attribute->IsFulfilled( | |
| 237 WebRequestData(url_request.get(), stage))); | |
| 238 EXPECT_TRUE(first_party_attribute->IsFulfilled( | |
| 239 WebRequestData(url_request.get(), stage))); | |
| 240 | |
| 241 url_request->set_first_party_for_cookies(url_b); | |
| 242 EXPECT_TRUE(third_party_attribute->IsFulfilled( | |
| 243 WebRequestData(url_request.get(), stage))); | |
| 244 EXPECT_FALSE(first_party_attribute->IsFulfilled( | |
| 245 WebRequestData(url_request.get(), stage))); | |
| 246 | |
| 247 url_request->set_first_party_for_cookies(url_a); | |
| 248 EXPECT_FALSE(third_party_attribute->IsFulfilled( | |
| 249 WebRequestData(url_request.get(), stage))); | |
| 250 EXPECT_TRUE(first_party_attribute->IsFulfilled( | |
| 251 WebRequestData(url_request.get(), stage))); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 // Testing WebRequestConditionAttributeStages. This iterates over all stages, | |
| 256 // and tests a couple of "stage" attributes -- one created with an empty set of | |
| 257 // applicable stages, one for each stage applicable for that stage, and one | |
| 258 // applicable in all stages. | |
| 259 TEST(WebRequestConditionAttributeTest, Stages) { | |
| 260 // Necessary for TestURLRequest. | |
| 261 base::MessageLoopForIO message_loop; | |
| 262 | |
| 263 typedef std::pair<RequestStage, const char*> StageNamePair; | |
| 264 static const StageNamePair active_stages[] = { | |
| 265 StageNamePair(ON_BEFORE_REQUEST, keys::kOnBeforeRequestEnum), | |
| 266 StageNamePair(ON_BEFORE_SEND_HEADERS, keys::kOnBeforeSendHeadersEnum), | |
| 267 StageNamePair(ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEnum), | |
| 268 StageNamePair(ON_AUTH_REQUIRED, keys::kOnAuthRequiredEnum) | |
| 269 }; | |
| 270 | |
| 271 // Check that exactly all active stages are considered in this test. | |
| 272 unsigned int covered_stages = 0; | |
| 273 for (size_t i = 0; i < arraysize(active_stages); ++i) | |
| 274 covered_stages |= active_stages[i].first; | |
| 275 EXPECT_EQ(kActiveStages, covered_stages); | |
| 276 | |
| 277 std::string error; | |
| 278 | |
| 279 // Create an attribute with an empty set of applicable stages. | |
| 280 base::ListValue empty_list; | |
| 281 scoped_refptr<const WebRequestConditionAttribute> empty_attribute = | |
| 282 WebRequestConditionAttribute::Create(keys::kStagesKey, | |
| 283 &empty_list, | |
| 284 &error); | |
| 285 EXPECT_EQ("", error); | |
| 286 ASSERT_TRUE(empty_attribute.get()); | |
| 287 EXPECT_EQ(std::string(keys::kStagesKey), empty_attribute->GetName()); | |
| 288 | |
| 289 // Create an attribute with all possible applicable stages. | |
| 290 base::ListValue all_stages; | |
| 291 for (size_t i = 0; i < arraysize(active_stages); ++i) | |
| 292 all_stages.AppendString(active_stages[i].second); | |
| 293 scoped_refptr<const WebRequestConditionAttribute> attribute_with_all = | |
| 294 WebRequestConditionAttribute::Create(keys::kStagesKey, | |
| 295 &all_stages, | |
| 296 &error); | |
| 297 EXPECT_EQ("", error); | |
| 298 ASSERT_TRUE(attribute_with_all.get()); | |
| 299 EXPECT_EQ(std::string(keys::kStagesKey), attribute_with_all->GetName()); | |
| 300 | |
| 301 // Create one attribute for each single stage, to be applicable in that stage. | |
| 302 std::vector<scoped_refptr<const WebRequestConditionAttribute> > | |
| 303 one_stage_attributes; | |
| 304 | |
| 305 for (size_t i = 0; i < arraysize(active_stages); ++i) { | |
| 306 base::ListValue single_stage_list; | |
| 307 single_stage_list.AppendString(active_stages[i].second); | |
| 308 one_stage_attributes.push_back( | |
| 309 WebRequestConditionAttribute::Create(keys::kStagesKey, | |
| 310 &single_stage_list, | |
| 311 &error)); | |
| 312 EXPECT_EQ("", error); | |
| 313 ASSERT_TRUE(one_stage_attributes.back().get() != NULL); | |
| 314 } | |
| 315 | |
| 316 const GURL url_empty; | |
| 317 net::TestURLRequestContext context; | |
| 318 net::TestDelegate delegate; | |
| 319 scoped_ptr<net::URLRequest> url_request( | |
| 320 context.CreateRequest(url_empty, net::DEFAULT_PRIORITY, &delegate, NULL)); | |
| 321 | |
| 322 for (size_t i = 0; i < arraysize(active_stages); ++i) { | |
| 323 EXPECT_FALSE(empty_attribute->IsFulfilled( | |
| 324 WebRequestData(url_request.get(), active_stages[i].first))); | |
| 325 | |
| 326 for (size_t j = 0; j < one_stage_attributes.size(); ++j) { | |
| 327 EXPECT_EQ(i == j, | |
| 328 one_stage_attributes[j]->IsFulfilled( | |
| 329 WebRequestData(url_request.get(), active_stages[i].first))); | |
| 330 } | |
| 331 | |
| 332 EXPECT_TRUE(attribute_with_all->IsFulfilled( | |
| 333 WebRequestData(url_request.get(), active_stages[i].first))); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 namespace { | |
| 338 | |
| 339 // Builds a vector of vectors of string pointers from an array of strings. | |
| 340 // |array| is in fact a sequence of arrays. The array |sizes| captures the sizes | |
| 341 // of all parts of |array|, and |size| is the length of |sizes| itself. | |
| 342 // Example (this is pseudo-code, not C++): | |
| 343 // array = { "a", "b", "c", "d", "e", "f" } | |
| 344 // sizes = { 2, 0, 4 } | |
| 345 // size = 3 | |
| 346 // results in out == { {&"a", &"b"}, {}, {&"c", &"d", &"e", &"f"} } | |
| 347 void GetArrayAsVector(const std::string array[], | |
| 348 const size_t sizes[], | |
| 349 const size_t size, | |
| 350 std::vector< std::vector<const std::string*> >* out) { | |
| 351 out->clear(); | |
| 352 size_t next = 0; | |
| 353 for (size_t i = 0; i < size; ++i) { | |
| 354 out->push_back(std::vector<const std::string*>()); | |
| 355 for (size_t j = next; j < next + sizes[i]; ++j) { | |
| 356 out->back().push_back(&(array[j])); | |
| 357 } | |
| 358 next += sizes[i]; | |
| 359 } | |
| 360 } | |
| 361 | |
| 362 // Builds a DictionaryValue from an array of the form {name1, value1, name2, | |
| 363 // value2, ...}. Values for the same key are grouped in a ListValue. | |
| 364 scoped_ptr<base::DictionaryValue> GetDictionaryFromArray( | |
| 365 const std::vector<const std::string*>& array) { | |
| 366 const size_t length = array.size(); | |
| 367 CHECK(length % 2 == 0); | |
| 368 | |
| 369 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue); | |
| 370 for (size_t i = 0; i < length; i += 2) { | |
| 371 const std::string* name = array[i]; | |
| 372 const std::string* value = array[i+1]; | |
| 373 if (dictionary->HasKey(*name)) { | |
| 374 base::Value* entry = NULL; | |
| 375 scoped_ptr<base::Value> entry_owned; | |
| 376 base::ListValue* list = NULL; | |
| 377 if (!dictionary->GetWithoutPathExpansion(*name, &entry)) | |
| 378 return scoped_ptr<base::DictionaryValue>(); | |
| 379 switch (entry->GetType()) { | |
| 380 case base::Value::TYPE_STRING: | |
| 381 // Replace the present string with a list. | |
| 382 list = new base::ListValue; | |
| 383 // Ignoring return value, we already verified the entry is there. | |
| 384 dictionary->RemoveWithoutPathExpansion(*name, &entry_owned); | |
| 385 list->Append(entry_owned.release()); | |
| 386 list->Append(new base::StringValue(*value)); | |
| 387 dictionary->SetWithoutPathExpansion(*name, list); | |
| 388 break; | |
| 389 case base::Value::TYPE_LIST: // Just append to the list. | |
| 390 CHECK(entry->GetAsList(&list)); | |
| 391 list->Append(new base::StringValue(*value)); | |
| 392 break; | |
| 393 default: | |
| 394 NOTREACHED(); // We never put other Values here. | |
| 395 return scoped_ptr<base::DictionaryValue>(); | |
| 396 } | |
| 397 } else { | |
| 398 dictionary->SetString(*name, *value); | |
| 399 } | |
| 400 } | |
| 401 return dictionary.Pass(); | |
| 402 } | |
| 403 | |
| 404 // Returns whether the response headers from |url_request| satisfy the match | |
| 405 // criteria given in |tests|. For at least one |i| all tests from |tests[i]| | |
| 406 // must pass. If |positive_test| is true, the dictionary is interpreted as the | |
| 407 // containsHeaders property of a RequestMatcher, otherwise as | |
| 408 // doesNotContainHeaders. | |
| 409 void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests, | |
| 410 const std::string& key, | |
| 411 RequestStage stage, | |
| 412 net::URLRequest* url_request, | |
| 413 bool* result) { | |
| 414 base::ListValue contains_headers; | |
| 415 for (size_t i = 0; i < tests.size(); ++i) { | |
| 416 scoped_ptr<base::DictionaryValue> temp(GetDictionaryFromArray(tests[i])); | |
| 417 ASSERT_TRUE(temp.get()); | |
| 418 contains_headers.Append(temp.release()); | |
| 419 } | |
| 420 | |
| 421 std::string error; | |
| 422 scoped_refptr<const WebRequestConditionAttribute> attribute = | |
| 423 WebRequestConditionAttribute::Create(key, &contains_headers, &error); | |
| 424 ASSERT_EQ("", error); | |
| 425 ASSERT_TRUE(attribute.get()); | |
| 426 EXPECT_EQ(key, attribute->GetName()); | |
| 427 | |
| 428 *result = attribute->IsFulfilled(WebRequestData( | |
| 429 url_request, stage, url_request->response_headers())); | |
| 430 } | |
| 431 | |
| 432 } // namespace | |
| 433 | |
| 434 // Here we test WebRequestConditionAttributeRequestHeaders for matching | |
| 435 // correctly against request headers. This test is not as extensive as | |
| 436 // "ResponseHeaders" (below), because the header-matching code is shared | |
| 437 // by both types of condition attributes, so it is enough to test it once. | |
| 438 TEST(WebRequestConditionAttributeTest, RequestHeaders) { | |
| 439 // Necessary for TestURLRequest. | |
| 440 base::MessageLoopForIO message_loop; | |
| 441 | |
| 442 net::TestURLRequestContext context; | |
| 443 net::TestDelegate delegate; | |
| 444 scoped_ptr<net::URLRequest> url_request( | |
| 445 context.CreateRequest(GURL("http://example.com"), // Dummy URL. | |
| 446 net::DEFAULT_PRIORITY, | |
| 447 &delegate, | |
| 448 NULL)); | |
| 449 url_request->SetExtraRequestHeaderByName( | |
| 450 "Custom-header", "custom/value", true /* overwrite */); | |
| 451 url_request->Start(); | |
| 452 base::MessageLoop::current()->Run(); | |
| 453 | |
| 454 std::vector<std::vector<const std::string*> > tests; | |
| 455 bool result = false; | |
| 456 | |
| 457 const RequestStage stage = ON_BEFORE_SEND_HEADERS; | |
| 458 | |
| 459 // First set of test data -- passing conjunction. | |
| 460 const std::string kPassingCondition[] = { | |
| 461 keys::kNameContainsKey, "CuStOm", // Header names are case insensitive. | |
| 462 keys::kNameEqualsKey, "custom-header", | |
| 463 keys::kValueSuffixKey, "alue", | |
| 464 keys::kValuePrefixKey, "custom/value" | |
| 465 }; | |
| 466 const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) }; | |
| 467 GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests); | |
| 468 // Positive filter, passing (conjunction of tests). | |
| 469 MatchAndCheck( | |
| 470 tests, keys::kRequestHeadersKey, stage, url_request.get(), &result); | |
| 471 EXPECT_TRUE(result); | |
| 472 // Negative filter, failing (conjunction of tests). | |
| 473 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, | |
| 474 url_request.get(), &result); | |
| 475 EXPECT_FALSE(result); | |
| 476 | |
| 477 // Second set of test data -- failing disjunction. | |
| 478 const std::string kFailCondition[] = { | |
| 479 keys::kNameSuffixKey, "Custom", // Test 1. | |
| 480 keys::kNameEqualsKey, "ustom-valu", // Test 2. | |
| 481 keys::kValuePrefixKey, "custom ", // Test 3. | |
| 482 keys::kValueContainsKey, " value" // Test 4. | |
| 483 }; | |
| 484 const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u }; | |
| 485 GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests); | |
| 486 // Positive filter, failing (disjunction of tests). | |
| 487 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(), | |
| 488 &result); | |
| 489 EXPECT_FALSE(result); | |
| 490 // Negative filter, passing (disjunction of tests). | |
| 491 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, | |
| 492 url_request.get(), &result); | |
| 493 EXPECT_TRUE(result); | |
| 494 | |
| 495 // Third set of test data, corner case -- empty disjunction. | |
| 496 GetArrayAsVector(NULL, NULL, 0u, &tests); | |
| 497 // Positive filter, failing (no test to pass). | |
| 498 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(), | |
| 499 &result); | |
| 500 EXPECT_FALSE(result); | |
| 501 // Negative filter, passing (no test to fail). | |
| 502 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, | |
| 503 url_request.get(), &result); | |
| 504 EXPECT_TRUE(result); | |
| 505 | |
| 506 // Fourth set of test data, corner case -- empty conjunction. | |
| 507 const size_t kEmptyConjunctionSizes[] = { 0u }; | |
| 508 GetArrayAsVector(NULL, kEmptyConjunctionSizes, 1u, &tests); | |
| 509 // Positive filter, passing (trivial test). | |
| 510 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(), | |
| 511 &result); | |
| 512 EXPECT_TRUE(result); | |
| 513 // Negative filter, failing. | |
| 514 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage, | |
| 515 url_request.get(), &result); | |
| 516 EXPECT_FALSE(result); | |
| 517 } | |
| 518 | |
| 519 // Here we test WebRequestConditionAttributeResponseHeaders for: | |
| 520 // 1. Correct implementation of prefix/suffix/contains/equals matching. | |
| 521 // 2. Performing logical disjunction (||) between multiple specifications. | |
| 522 // 3. Negating the match in case of 'doesNotContainHeaders'. | |
| 523 TEST(WebRequestConditionAttributeTest, ResponseHeaders) { | |
| 524 // Necessary for TestURLRequest. | |
| 525 base::MessageLoopForIO message_loop; | |
| 526 | |
| 527 net::test_server::EmbeddedTestServer test_server; | |
| 528 test_server.ServeFilesFromDirectory(TestDataPath( | |
| 529 "chrome/test/data/extensions/api_test/webrequest/declarative")); | |
| 530 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady()); | |
| 531 | |
| 532 net::TestURLRequestContext context; | |
| 533 net::TestDelegate delegate; | |
| 534 scoped_ptr<net::URLRequest> url_request( | |
| 535 context.CreateRequest(test_server.GetURL("/headers.html"), | |
| 536 net::DEFAULT_PRIORITY, | |
| 537 &delegate, | |
| 538 NULL)); | |
| 539 url_request->Start(); | |
| 540 base::MessageLoop::current()->Run(); | |
| 541 | |
| 542 // In all the tests below we assume that the server includes the headers | |
| 543 // Custom-Header: custom/value | |
| 544 // Custom-Header-B: valueA | |
| 545 // Custom-Header-B: valueB | |
| 546 // Custom-Header-C: valueC, valueD | |
| 547 // Custom-Header-D: | |
| 548 // in the response, but does not include "Non-existing: void". | |
| 549 | |
| 550 std::vector< std::vector<const std::string*> > tests; | |
| 551 bool result; | |
| 552 | |
| 553 const RequestStage stage = ON_HEADERS_RECEIVED; | |
| 554 | |
| 555 // 1.a. -- All these tests should pass. | |
| 556 const std::string kPassingCondition[] = { | |
| 557 keys::kNamePrefixKey, "Custom", | |
| 558 keys::kNameSuffixKey, "m-header", // Header names are case insensitive. | |
| 559 keys::kValueContainsKey, "alu", | |
| 560 keys::kValueEqualsKey, "custom/value" | |
| 561 }; | |
| 562 const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) }; | |
| 563 GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests); | |
| 564 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 565 &result); | |
| 566 EXPECT_TRUE(result); | |
| 567 | |
| 568 // 1.b. -- None of the following tests in the discjunction should pass. | |
| 569 const std::string kFailCondition[] = { | |
| 570 keys::kNamePrefixKey, " Custom", // Test 1. | |
| 571 keys::kNameContainsKey, " -", // Test 2. | |
| 572 keys::kValueSuffixKey, "alu", // Test 3. | |
| 573 keys::kValueEqualsKey, "custom" // Test 4. | |
| 574 }; | |
| 575 const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u }; | |
| 576 GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests); | |
| 577 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 578 &result); | |
| 579 EXPECT_FALSE(result); | |
| 580 | |
| 581 // 1.c. -- This should fail (mixing name and value from different headers) | |
| 582 const std::string kMixingCondition[] = { | |
| 583 keys::kNameSuffixKey, "Header-B", | |
| 584 keys::kValueEqualsKey, "custom/value" | |
| 585 }; | |
| 586 const size_t kMixingConditionSizes[] = { arraysize(kMixingCondition) }; | |
| 587 GetArrayAsVector(kMixingCondition, kMixingConditionSizes, 1u, &tests); | |
| 588 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 589 &result); | |
| 590 EXPECT_FALSE(result); | |
| 591 | |
| 592 // 1.d. -- Test handling multiple values for one header (both should pass). | |
| 593 const std::string kMoreValues1[] = { | |
| 594 keys::kNameEqualsKey, "Custom-header-b", | |
| 595 keys::kValueEqualsKey, "valueA" | |
| 596 }; | |
| 597 const size_t kMoreValues1Sizes[] = { arraysize(kMoreValues1) }; | |
| 598 GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, 1u, &tests); | |
| 599 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 600 &result); | |
| 601 EXPECT_TRUE(result); | |
| 602 const std::string kMoreValues2[] = { | |
| 603 keys::kNameEqualsKey, "Custom-header-b", | |
| 604 keys::kValueEqualsKey, "valueB" | |
| 605 }; | |
| 606 const size_t kMoreValues2Sizes[] = { arraysize(kMoreValues2) }; | |
| 607 GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, 1u, &tests); | |
| 608 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 609 &result); | |
| 610 EXPECT_TRUE(result); | |
| 611 | |
| 612 // 1.e. -- This should fail as conjunction but pass as disjunction. | |
| 613 const std::string kConflict[] = { | |
| 614 keys::kNameSuffixKey, "Header", // True for some header. | |
| 615 keys::kNameContainsKey, "Header-B" // True for a different header. | |
| 616 }; | |
| 617 // First disjunction, no conflict. | |
| 618 const size_t kNoConflictSizes[] = { 2u, 2u }; | |
| 619 GetArrayAsVector(kConflict, kNoConflictSizes, 2u, &tests); | |
| 620 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 621 &result); | |
| 622 EXPECT_TRUE(result); | |
| 623 // Then conjunction, conflict. | |
| 624 const size_t kConflictSizes[] = { arraysize(kConflict) }; | |
| 625 GetArrayAsVector(kConflict, kConflictSizes, 1u, &tests); | |
| 626 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 627 &result); | |
| 628 EXPECT_FALSE(result); | |
| 629 | |
| 630 // 1.f. -- This should pass, checking for correct treatment of ',' in values. | |
| 631 const std::string kComma[] = { | |
| 632 keys::kNameSuffixKey, "Header-C", | |
| 633 keys::kValueEqualsKey, "valueC, valueD" | |
| 634 }; | |
| 635 const size_t kCommaSizes[] = { arraysize(kComma) }; | |
| 636 GetArrayAsVector(kComma, kCommaSizes, 1u, &tests); | |
| 637 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 638 &result); | |
| 639 EXPECT_TRUE(result); | |
| 640 | |
| 641 // 1.g. -- This should pass, empty values are values as well. | |
| 642 const std::string kEmpty[] = { | |
| 643 keys::kNameEqualsKey, "custom-header-d", | |
| 644 keys::kValueEqualsKey, "" | |
| 645 }; | |
| 646 const size_t kEmptySizes[] = { arraysize(kEmpty) }; | |
| 647 GetArrayAsVector(kEmpty, kEmptySizes, 1u, &tests); | |
| 648 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 649 &result); | |
| 650 EXPECT_TRUE(result); | |
| 651 | |
| 652 // 1.h. -- Values are case-sensitive, this should fail. | |
| 653 const std::string kLowercase[] = { | |
| 654 keys::kNameEqualsKey, "Custom-header-b", | |
| 655 keys::kValuePrefixKey, "valueb", // valueb != valueB | |
| 656 keys::kNameEqualsKey, "Custom-header-b", | |
| 657 keys::kValueSuffixKey, "valueb", | |
| 658 keys::kNameEqualsKey, "Custom-header-b", | |
| 659 keys::kValueContainsKey, "valueb", | |
| 660 keys::kNameEqualsKey, "Custom-header-b", | |
| 661 keys::kValueEqualsKey, "valueb" | |
| 662 }; | |
| 663 const size_t kLowercaseSizes[] = { 4u, 4u, 4u, 4u }; // As disjunction. | |
| 664 GetArrayAsVector(kLowercase, kLowercaseSizes, 4u, &tests); | |
| 665 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 666 &result); | |
| 667 EXPECT_FALSE(result); | |
| 668 | |
| 669 // 1.i. -- Names are case-insensitive, this should pass. | |
| 670 const std::string kUppercase[] = { | |
| 671 keys::kNamePrefixKey, "CUSTOM-HEADER-B", | |
| 672 keys::kNameSuffixKey, "CUSTOM-HEADER-B", | |
| 673 keys::kNameEqualsKey, "CUSTOM-HEADER-B", | |
| 674 keys::kNameContainsKey, "CUSTOM-HEADER-B" | |
| 675 }; | |
| 676 const size_t kUppercaseSizes[] = { arraysize(kUppercase) }; // Conjunction. | |
| 677 GetArrayAsVector(kUppercase, kUppercaseSizes, 1u, &tests); | |
| 678 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 679 &result); | |
| 680 EXPECT_TRUE(result); | |
| 681 | |
| 682 // 2.a. -- This should pass as disjunction, because one of the tests passes. | |
| 683 const std::string kDisjunction[] = { | |
| 684 keys::kNamePrefixKey, "Non-existing", // This one fails. | |
| 685 keys::kNameSuffixKey, "Non-existing", // This one fails. | |
| 686 keys::kValueEqualsKey, "void", // This one fails. | |
| 687 keys::kValueContainsKey, "alu" // This passes. | |
| 688 }; | |
| 689 const size_t kDisjunctionSizes[] = { 2u, 2u, 2u, 2u }; | |
| 690 GetArrayAsVector(kDisjunction, kDisjunctionSizes, 4u, &tests); | |
| 691 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(), | |
| 692 &result); | |
| 693 EXPECT_TRUE(result); | |
| 694 | |
| 695 // 3.a. -- This should pass. | |
| 696 const std::string kNonExistent[] = { | |
| 697 keys::kNameEqualsKey, "Non-existing", | |
| 698 keys::kValueEqualsKey, "void" | |
| 699 }; | |
| 700 const size_t kNonExistentSizes[] = { arraysize(kNonExistent) }; | |
| 701 GetArrayAsVector(kNonExistent, kNonExistentSizes, 1u, &tests); | |
| 702 MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage, | |
| 703 url_request.get(), &result); | |
| 704 EXPECT_TRUE(result); | |
| 705 | |
| 706 // 3.b. -- This should fail. | |
| 707 const std::string kExisting[] = { | |
| 708 keys::kNameEqualsKey, "custom-header-b", | |
| 709 keys::kValueEqualsKey, "valueB" | |
| 710 }; | |
| 711 const size_t kExistingSize[] = { arraysize(kExisting) }; | |
| 712 GetArrayAsVector(kExisting, kExistingSize, 1u, &tests); | |
| 713 MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage, | |
| 714 url_request.get(), &result); | |
| 715 EXPECT_FALSE(result); | |
| 716 } | |
| 717 | |
| 718 } // namespace | |
| 719 } // namespace extensions | |
| OLD | NEW |