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