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
;
26 using content::ResourceType
;
28 namespace extensions
{
30 namespace keys
= declarative_webrequest_constants
;
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
;
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.
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
60 result
= WebRequestConditionAttribute::Create(
61 keys::kResourceTypeKey
, &string_value
, &error
);
62 EXPECT_FALSE(error
.empty());
63 EXPECT_FALSE(result
.get());
66 result
= WebRequestConditionAttribute::Create(
67 keys::kContentTypeKey
, &string_value
, &error
);
68 EXPECT_FALSE(error
.empty());
69 EXPECT_FALSE(result
.get());
73 result
= WebRequestConditionAttribute::Create(
74 keys::kResourceTypeKey
, &resource_types
, &error
);
76 ASSERT_TRUE(result
.get());
77 EXPECT_EQ(WebRequestConditionAttribute::CONDITION_RESOURCE_TYPE
,
79 EXPECT_EQ(std::string(keys::kResourceTypeKey
), result
->GetName());
82 TEST(WebRequestConditionAttributeTest
, ResourceType
) {
83 // Necessary for TestURLRequest.
84 base::MessageLoopForIO message_loop
;
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
);
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
, NULL
));
102 content::ResourceRequestInfo::AllocateForTesting(
103 url_request_ok
.get(),
104 content::RESOURCE_TYPE_SUB_FRAME
,
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
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
, NULL
));
118 content::ResourceRequestInfo::AllocateForTesting(
119 url_request_fail
.get(),
120 content::RESOURCE_TYPE_MAIN_FRAME
,
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
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
;
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(
148 context
.CreateRequest(test_server
.GetURL("/headers.html"),
149 net::DEFAULT_PRIORITY
,
152 url_request
->Start();
153 base::MessageLoop::current()->Run();
155 base::ListValue content_types
;
156 content_types
.Append(new base::StringValue("text/plain"));
157 scoped_refptr
<const WebRequestConditionAttribute
> attribute_include
=
158 WebRequestConditionAttribute::Create(
159 keys::kContentTypeKey
, &content_types
, &error
);
160 EXPECT_EQ("", error
);
161 ASSERT_TRUE(attribute_include
.get());
162 EXPECT_FALSE(attribute_include
->IsFulfilled(
163 WebRequestData(url_request
.get(), ON_BEFORE_REQUEST
,
164 url_request
->response_headers())));
165 EXPECT_TRUE(attribute_include
->IsFulfilled(
166 WebRequestData(url_request
.get(), ON_HEADERS_RECEIVED
,
167 url_request
->response_headers())));
168 EXPECT_EQ(std::string(keys::kContentTypeKey
), attribute_include
->GetName());
170 scoped_refptr
<const WebRequestConditionAttribute
> attribute_exclude
=
171 WebRequestConditionAttribute::Create(
172 keys::kExcludeContentTypeKey
, &content_types
, &error
);
173 EXPECT_EQ("", error
);
174 ASSERT_TRUE(attribute_exclude
.get());
175 EXPECT_FALSE(attribute_exclude
->IsFulfilled(
176 WebRequestData(url_request
.get(), ON_HEADERS_RECEIVED
,
177 url_request
->response_headers())));
179 content_types
.Clear();
180 content_types
.Append(new base::StringValue("something/invalid"));
181 scoped_refptr
<const WebRequestConditionAttribute
> attribute_unincluded
=
182 WebRequestConditionAttribute::Create(
183 keys::kContentTypeKey
, &content_types
, &error
);
184 EXPECT_EQ("", error
);
185 ASSERT_TRUE(attribute_unincluded
.get());
186 EXPECT_FALSE(attribute_unincluded
->IsFulfilled(
187 WebRequestData(url_request
.get(), ON_HEADERS_RECEIVED
,
188 url_request
->response_headers())));
190 scoped_refptr
<const WebRequestConditionAttribute
> attribute_unexcluded
=
191 WebRequestConditionAttribute::Create(
192 keys::kExcludeContentTypeKey
, &content_types
, &error
);
193 EXPECT_EQ("", error
);
194 ASSERT_TRUE(attribute_unexcluded
.get());
195 EXPECT_TRUE(attribute_unexcluded
->IsFulfilled(
196 WebRequestData(url_request
.get(), ON_HEADERS_RECEIVED
,
197 url_request
->response_headers())));
198 EXPECT_EQ(std::string(keys::kExcludeContentTypeKey
),
199 attribute_unexcluded
->GetName());
202 // Testing WebRequestConditionAttributeThirdParty.
203 TEST(WebRequestConditionAttributeTest
, ThirdParty
) {
204 // Necessary for TestURLRequest.
205 base::MessageLoopForIO message_loop
;
208 const FundamentalValue
value_true(true);
209 // This attribute matches only third party requests.
210 scoped_refptr
<const WebRequestConditionAttribute
> third_party_attribute
=
211 WebRequestConditionAttribute::Create(keys::kThirdPartyKey
,
214 ASSERT_EQ("", error
);
215 ASSERT_TRUE(third_party_attribute
.get());
216 EXPECT_EQ(std::string(keys::kThirdPartyKey
),
217 third_party_attribute
->GetName());
218 const FundamentalValue
value_false(false);
219 // This attribute matches only first party requests.
220 scoped_refptr
<const WebRequestConditionAttribute
> first_party_attribute
=
221 WebRequestConditionAttribute::Create(keys::kThirdPartyKey
,
224 ASSERT_EQ("", error
);
225 ASSERT_TRUE(first_party_attribute
.get());
226 EXPECT_EQ(std::string(keys::kThirdPartyKey
),
227 first_party_attribute
->GetName());
229 const GURL url_empty
;
230 const GURL
url_a("http://a.com");
231 const GURL
url_b("http://b.com");
232 net::TestURLRequestContext context
;
233 net::TestDelegate delegate
;
234 scoped_ptr
<net::URLRequest
> url_request(
235 context
.CreateRequest(url_a
, net::DEFAULT_PRIORITY
, &delegate
, NULL
));
237 for (unsigned int i
= 1; i
<= kLastActiveStage
; i
<<= 1) {
238 if (!(kActiveStages
& i
))
240 const RequestStage stage
= static_cast<RequestStage
>(i
);
241 url_request
->set_first_party_for_cookies(url_empty
);
242 EXPECT_FALSE(third_party_attribute
->IsFulfilled(
243 WebRequestData(url_request
.get(), stage
)));
244 EXPECT_TRUE(first_party_attribute
->IsFulfilled(
245 WebRequestData(url_request
.get(), stage
)));
247 url_request
->set_first_party_for_cookies(url_b
);
248 EXPECT_TRUE(third_party_attribute
->IsFulfilled(
249 WebRequestData(url_request
.get(), stage
)));
250 EXPECT_FALSE(first_party_attribute
->IsFulfilled(
251 WebRequestData(url_request
.get(), stage
)));
253 url_request
->set_first_party_for_cookies(url_a
);
254 EXPECT_FALSE(third_party_attribute
->IsFulfilled(
255 WebRequestData(url_request
.get(), stage
)));
256 EXPECT_TRUE(first_party_attribute
->IsFulfilled(
257 WebRequestData(url_request
.get(), stage
)));
261 // Testing WebRequestConditionAttributeStages. This iterates over all stages,
262 // and tests a couple of "stage" attributes -- one created with an empty set of
263 // applicable stages, one for each stage applicable for that stage, and one
264 // applicable in all stages.
265 TEST(WebRequestConditionAttributeTest
, Stages
) {
266 // Necessary for TestURLRequest.
267 base::MessageLoopForIO message_loop
;
269 typedef std::pair
<RequestStage
, const char*> StageNamePair
;
270 static const StageNamePair active_stages
[] = {
271 StageNamePair(ON_BEFORE_REQUEST
, keys::kOnBeforeRequestEnum
),
272 StageNamePair(ON_BEFORE_SEND_HEADERS
, keys::kOnBeforeSendHeadersEnum
),
273 StageNamePair(ON_HEADERS_RECEIVED
, keys::kOnHeadersReceivedEnum
),
274 StageNamePair(ON_AUTH_REQUIRED
, keys::kOnAuthRequiredEnum
)
277 // Check that exactly all active stages are considered in this test.
278 unsigned int covered_stages
= 0;
279 for (size_t i
= 0; i
< arraysize(active_stages
); ++i
)
280 covered_stages
|= active_stages
[i
].first
;
281 EXPECT_EQ(kActiveStages
, covered_stages
);
285 // Create an attribute with an empty set of applicable stages.
286 base::ListValue empty_list
;
287 scoped_refptr
<const WebRequestConditionAttribute
> empty_attribute
=
288 WebRequestConditionAttribute::Create(keys::kStagesKey
,
291 EXPECT_EQ("", error
);
292 ASSERT_TRUE(empty_attribute
.get());
293 EXPECT_EQ(std::string(keys::kStagesKey
), empty_attribute
->GetName());
295 // Create an attribute with all possible applicable stages.
296 base::ListValue all_stages
;
297 for (size_t i
= 0; i
< arraysize(active_stages
); ++i
)
298 all_stages
.AppendString(active_stages
[i
].second
);
299 scoped_refptr
<const WebRequestConditionAttribute
> attribute_with_all
=
300 WebRequestConditionAttribute::Create(keys::kStagesKey
,
303 EXPECT_EQ("", error
);
304 ASSERT_TRUE(attribute_with_all
.get());
305 EXPECT_EQ(std::string(keys::kStagesKey
), attribute_with_all
->GetName());
307 // Create one attribute for each single stage, to be applicable in that stage.
308 std::vector
<scoped_refptr
<const WebRequestConditionAttribute
> >
309 one_stage_attributes
;
311 for (size_t i
= 0; i
< arraysize(active_stages
); ++i
) {
312 base::ListValue single_stage_list
;
313 single_stage_list
.AppendString(active_stages
[i
].second
);
314 one_stage_attributes
.push_back(
315 WebRequestConditionAttribute::Create(keys::kStagesKey
,
318 EXPECT_EQ("", error
);
319 ASSERT_TRUE(one_stage_attributes
.back().get() != NULL
);
322 const GURL url_empty
;
323 net::TestURLRequestContext context
;
324 net::TestDelegate delegate
;
325 scoped_ptr
<net::URLRequest
> url_request(
326 context
.CreateRequest(url_empty
, net::DEFAULT_PRIORITY
, &delegate
, NULL
));
328 for (size_t i
= 0; i
< arraysize(active_stages
); ++i
) {
329 EXPECT_FALSE(empty_attribute
->IsFulfilled(
330 WebRequestData(url_request
.get(), active_stages
[i
].first
)));
332 for (size_t j
= 0; j
< one_stage_attributes
.size(); ++j
) {
334 one_stage_attributes
[j
]->IsFulfilled(
335 WebRequestData(url_request
.get(), active_stages
[i
].first
)));
338 EXPECT_TRUE(attribute_with_all
->IsFulfilled(
339 WebRequestData(url_request
.get(), active_stages
[i
].first
)));
345 // Builds a vector of vectors of string pointers from an array of strings.
346 // |array| is in fact a sequence of arrays. The array |sizes| captures the sizes
347 // of all parts of |array|, and |size| is the length of |sizes| itself.
348 // Example (this is pseudo-code, not C++):
349 // array = { "a", "b", "c", "d", "e", "f" }
350 // sizes = { 2, 0, 4 }
352 // results in out == { {&"a", &"b"}, {}, {&"c", &"d", &"e", &"f"} }
353 void GetArrayAsVector(const std::string array
[],
354 const size_t sizes
[],
356 std::vector
< std::vector
<const std::string
*> >* out
) {
359 for (size_t i
= 0; i
< size
; ++i
) {
360 out
->push_back(std::vector
<const std::string
*>());
361 for (size_t j
= next
; j
< next
+ sizes
[i
]; ++j
) {
362 out
->back().push_back(&(array
[j
]));
368 // Builds a DictionaryValue from an array of the form {name1, value1, name2,
369 // value2, ...}. Values for the same key are grouped in a ListValue.
370 scoped_ptr
<base::DictionaryValue
> GetDictionaryFromArray(
371 const std::vector
<const std::string
*>& array
) {
372 const size_t length
= array
.size();
373 CHECK(length
% 2 == 0);
375 scoped_ptr
<base::DictionaryValue
> dictionary(new base::DictionaryValue
);
376 for (size_t i
= 0; i
< length
; i
+= 2) {
377 const std::string
* name
= array
[i
];
378 const std::string
* value
= array
[i
+1];
379 if (dictionary
->HasKey(*name
)) {
380 base::Value
* entry
= NULL
;
381 scoped_ptr
<base::Value
> entry_owned
;
382 base::ListValue
* list
= NULL
;
383 if (!dictionary
->GetWithoutPathExpansion(*name
, &entry
))
384 return scoped_ptr
<base::DictionaryValue
>();
385 switch (entry
->GetType()) {
386 case base::Value::TYPE_STRING
:
387 // Replace the present string with a list.
388 list
= new base::ListValue
;
389 // Ignoring return value, we already verified the entry is there.
390 dictionary
->RemoveWithoutPathExpansion(*name
, &entry_owned
);
391 list
->Append(entry_owned
.release());
392 list
->Append(new base::StringValue(*value
));
393 dictionary
->SetWithoutPathExpansion(*name
, list
);
395 case base::Value::TYPE_LIST
: // Just append to the list.
396 CHECK(entry
->GetAsList(&list
));
397 list
->Append(new base::StringValue(*value
));
400 NOTREACHED(); // We never put other Values here.
401 return scoped_ptr
<base::DictionaryValue
>();
404 dictionary
->SetString(*name
, *value
);
407 return dictionary
.Pass();
410 // Returns whether the response headers from |url_request| satisfy the match
411 // criteria given in |tests|. For at least one |i| all tests from |tests[i]|
412 // must pass. If |positive_test| is true, the dictionary is interpreted as the
413 // containsHeaders property of a RequestMatcher, otherwise as
414 // doesNotContainHeaders.
415 void MatchAndCheck(const std::vector
< std::vector
<const std::string
*> >& tests
,
416 const std::string
& key
,
418 net::URLRequest
* url_request
,
420 base::ListValue contains_headers
;
421 for (size_t i
= 0; i
< tests
.size(); ++i
) {
422 scoped_ptr
<base::DictionaryValue
> temp(GetDictionaryFromArray(tests
[i
]));
423 ASSERT_TRUE(temp
.get());
424 contains_headers
.Append(temp
.release());
428 scoped_refptr
<const WebRequestConditionAttribute
> attribute
=
429 WebRequestConditionAttribute::Create(key
, &contains_headers
, &error
);
430 ASSERT_EQ("", error
);
431 ASSERT_TRUE(attribute
.get());
432 EXPECT_EQ(key
, attribute
->GetName());
434 *result
= attribute
->IsFulfilled(WebRequestData(
435 url_request
, stage
, url_request
->response_headers()));
440 // Here we test WebRequestConditionAttributeRequestHeaders for matching
441 // correctly against request headers. This test is not as extensive as
442 // "ResponseHeaders" (below), because the header-matching code is shared
443 // by both types of condition attributes, so it is enough to test it once.
444 TEST(WebRequestConditionAttributeTest
, RequestHeaders
) {
445 // Necessary for TestURLRequest.
446 base::MessageLoopForIO message_loop
;
448 net::TestURLRequestContext context
;
449 net::TestDelegate delegate
;
450 scoped_ptr
<net::URLRequest
> url_request(
451 context
.CreateRequest(GURL("http://example.com"), // Dummy URL.
452 net::DEFAULT_PRIORITY
,
455 url_request
->SetExtraRequestHeaderByName(
456 "Custom-header", "custom/value", true /* overwrite */);
457 url_request
->Start();
458 base::MessageLoop::current()->Run();
460 std::vector
<std::vector
<const std::string
*> > tests
;
463 const RequestStage stage
= ON_BEFORE_SEND_HEADERS
;
465 // First set of test data -- passing conjunction.
466 const std::string kPassingCondition
[] = {
467 keys::kNameContainsKey
, "CuStOm", // Header names are case insensitive.
468 keys::kNameEqualsKey
, "custom-header",
469 keys::kValueSuffixKey
, "alue",
470 keys::kValuePrefixKey
, "custom/value"
472 const size_t kPassingConditionSizes
[] = { arraysize(kPassingCondition
) };
473 GetArrayAsVector(kPassingCondition
, kPassingConditionSizes
, 1u, &tests
);
474 // Positive filter, passing (conjunction of tests).
476 tests
, keys::kRequestHeadersKey
, stage
, url_request
.get(), &result
);
478 // Negative filter, failing (conjunction of tests).
479 MatchAndCheck(tests
, keys::kExcludeRequestHeadersKey
, stage
,
480 url_request
.get(), &result
);
481 EXPECT_FALSE(result
);
483 // Second set of test data -- failing disjunction.
484 const std::string kFailCondition
[] = {
485 keys::kNameSuffixKey
, "Custom", // Test 1.
486 keys::kNameEqualsKey
, "ustom-valu", // Test 2.
487 keys::kValuePrefixKey
, "custom ", // Test 3.
488 keys::kValueContainsKey
, " value" // Test 4.
490 const size_t kFailConditionSizes
[] = { 2u, 2u, 2u, 2u };
491 GetArrayAsVector(kFailCondition
, kFailConditionSizes
, 4u, &tests
);
492 // Positive filter, failing (disjunction of tests).
493 MatchAndCheck(tests
, keys::kRequestHeadersKey
, stage
, url_request
.get(),
495 EXPECT_FALSE(result
);
496 // Negative filter, passing (disjunction of tests).
497 MatchAndCheck(tests
, keys::kExcludeRequestHeadersKey
, stage
,
498 url_request
.get(), &result
);
501 // Third set of test data, corner case -- empty disjunction.
502 GetArrayAsVector(NULL
, NULL
, 0u, &tests
);
503 // Positive filter, failing (no test to pass).
504 MatchAndCheck(tests
, keys::kRequestHeadersKey
, stage
, url_request
.get(),
506 EXPECT_FALSE(result
);
507 // Negative filter, passing (no test to fail).
508 MatchAndCheck(tests
, keys::kExcludeRequestHeadersKey
, stage
,
509 url_request
.get(), &result
);
512 // Fourth set of test data, corner case -- empty conjunction.
513 const size_t kEmptyConjunctionSizes
[] = { 0u };
514 GetArrayAsVector(NULL
, kEmptyConjunctionSizes
, 1u, &tests
);
515 // Positive filter, passing (trivial test).
516 MatchAndCheck(tests
, keys::kRequestHeadersKey
, stage
, url_request
.get(),
519 // Negative filter, failing.
520 MatchAndCheck(tests
, keys::kExcludeRequestHeadersKey
, stage
,
521 url_request
.get(), &result
);
522 EXPECT_FALSE(result
);
525 // Here we test WebRequestConditionAttributeResponseHeaders for:
526 // 1. Correct implementation of prefix/suffix/contains/equals matching.
527 // 2. Performing logical disjunction (||) between multiple specifications.
528 // 3. Negating the match in case of 'doesNotContainHeaders'.
529 TEST(WebRequestConditionAttributeTest
, ResponseHeaders
) {
530 // Necessary for TestURLRequest.
531 base::MessageLoopForIO message_loop
;
533 net::test_server::EmbeddedTestServer test_server
;
534 test_server
.ServeFilesFromDirectory(TestDataPath(
535 "chrome/test/data/extensions/api_test/webrequest/declarative"));
536 ASSERT_TRUE(test_server
.InitializeAndWaitUntilReady());
538 net::TestURLRequestContext context
;
539 net::TestDelegate delegate
;
540 scoped_ptr
<net::URLRequest
> url_request(
541 context
.CreateRequest(test_server
.GetURL("/headers.html"),
542 net::DEFAULT_PRIORITY
,
545 url_request
->Start();
546 base::MessageLoop::current()->Run();
548 // In all the tests below we assume that the server includes the headers
549 // Custom-Header: custom/value
550 // Custom-Header-B: valueA
551 // Custom-Header-B: valueB
552 // Custom-Header-C: valueC, valueD
554 // in the response, but does not include "Non-existing: void".
556 std::vector
< std::vector
<const std::string
*> > tests
;
559 const RequestStage stage
= ON_HEADERS_RECEIVED
;
561 // 1.a. -- All these tests should pass.
562 const std::string kPassingCondition
[] = {
563 keys::kNamePrefixKey
, "Custom",
564 keys::kNameSuffixKey
, "m-header", // Header names are case insensitive.
565 keys::kValueContainsKey
, "alu",
566 keys::kValueEqualsKey
, "custom/value"
568 const size_t kPassingConditionSizes
[] = { arraysize(kPassingCondition
) };
569 GetArrayAsVector(kPassingCondition
, kPassingConditionSizes
, 1u, &tests
);
570 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
574 // 1.b. -- None of the following tests in the discjunction should pass.
575 const std::string kFailCondition
[] = {
576 keys::kNamePrefixKey
, " Custom", // Test 1.
577 keys::kNameContainsKey
, " -", // Test 2.
578 keys::kValueSuffixKey
, "alu", // Test 3.
579 keys::kValueEqualsKey
, "custom" // Test 4.
581 const size_t kFailConditionSizes
[] = { 2u, 2u, 2u, 2u };
582 GetArrayAsVector(kFailCondition
, kFailConditionSizes
, 4u, &tests
);
583 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
585 EXPECT_FALSE(result
);
587 // 1.c. -- This should fail (mixing name and value from different headers)
588 const std::string kMixingCondition
[] = {
589 keys::kNameSuffixKey
, "Header-B",
590 keys::kValueEqualsKey
, "custom/value"
592 const size_t kMixingConditionSizes
[] = { arraysize(kMixingCondition
) };
593 GetArrayAsVector(kMixingCondition
, kMixingConditionSizes
, 1u, &tests
);
594 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
596 EXPECT_FALSE(result
);
598 // 1.d. -- Test handling multiple values for one header (both should pass).
599 const std::string kMoreValues1
[] = {
600 keys::kNameEqualsKey
, "Custom-header-b",
601 keys::kValueEqualsKey
, "valueA"
603 const size_t kMoreValues1Sizes
[] = { arraysize(kMoreValues1
) };
604 GetArrayAsVector(kMoreValues1
, kMoreValues1Sizes
, 1u, &tests
);
605 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
608 const std::string kMoreValues2
[] = {
609 keys::kNameEqualsKey
, "Custom-header-b",
610 keys::kValueEqualsKey
, "valueB"
612 const size_t kMoreValues2Sizes
[] = { arraysize(kMoreValues2
) };
613 GetArrayAsVector(kMoreValues2
, kMoreValues2Sizes
, 1u, &tests
);
614 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
618 // 1.e. -- This should fail as conjunction but pass as disjunction.
619 const std::string kConflict
[] = {
620 keys::kNameSuffixKey
, "Header", // True for some header.
621 keys::kNameContainsKey
, "Header-B" // True for a different header.
623 // First disjunction, no conflict.
624 const size_t kNoConflictSizes
[] = { 2u, 2u };
625 GetArrayAsVector(kConflict
, kNoConflictSizes
, 2u, &tests
);
626 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
629 // Then conjunction, conflict.
630 const size_t kConflictSizes
[] = { arraysize(kConflict
) };
631 GetArrayAsVector(kConflict
, kConflictSizes
, 1u, &tests
);
632 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
634 EXPECT_FALSE(result
);
636 // 1.f. -- This should pass, checking for correct treatment of ',' in values.
637 const std::string kComma
[] = {
638 keys::kNameSuffixKey
, "Header-C",
639 keys::kValueEqualsKey
, "valueC, valueD"
641 const size_t kCommaSizes
[] = { arraysize(kComma
) };
642 GetArrayAsVector(kComma
, kCommaSizes
, 1u, &tests
);
643 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
647 // 1.g. -- This should pass, empty values are values as well.
648 const std::string kEmpty
[] = {
649 keys::kNameEqualsKey
, "custom-header-d",
650 keys::kValueEqualsKey
, ""
652 const size_t kEmptySizes
[] = { arraysize(kEmpty
) };
653 GetArrayAsVector(kEmpty
, kEmptySizes
, 1u, &tests
);
654 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
658 // 1.h. -- Values are case-sensitive, this should fail.
659 const std::string kLowercase
[] = {
660 keys::kNameEqualsKey
, "Custom-header-b",
661 keys::kValuePrefixKey
, "valueb", // valueb != valueB
662 keys::kNameEqualsKey
, "Custom-header-b",
663 keys::kValueSuffixKey
, "valueb",
664 keys::kNameEqualsKey
, "Custom-header-b",
665 keys::kValueContainsKey
, "valueb",
666 keys::kNameEqualsKey
, "Custom-header-b",
667 keys::kValueEqualsKey
, "valueb"
669 const size_t kLowercaseSizes
[] = { 4u, 4u, 4u, 4u }; // As disjunction.
670 GetArrayAsVector(kLowercase
, kLowercaseSizes
, 4u, &tests
);
671 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
673 EXPECT_FALSE(result
);
675 // 1.i. -- Names are case-insensitive, this should pass.
676 const std::string kUppercase
[] = {
677 keys::kNamePrefixKey
, "CUSTOM-HEADER-B",
678 keys::kNameSuffixKey
, "CUSTOM-HEADER-B",
679 keys::kNameEqualsKey
, "CUSTOM-HEADER-B",
680 keys::kNameContainsKey
, "CUSTOM-HEADER-B"
682 const size_t kUppercaseSizes
[] = { arraysize(kUppercase
) }; // Conjunction.
683 GetArrayAsVector(kUppercase
, kUppercaseSizes
, 1u, &tests
);
684 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
688 // 2.a. -- This should pass as disjunction, because one of the tests passes.
689 const std::string kDisjunction
[] = {
690 keys::kNamePrefixKey
, "Non-existing", // This one fails.
691 keys::kNameSuffixKey
, "Non-existing", // This one fails.
692 keys::kValueEqualsKey
, "void", // This one fails.
693 keys::kValueContainsKey
, "alu" // This passes.
695 const size_t kDisjunctionSizes
[] = { 2u, 2u, 2u, 2u };
696 GetArrayAsVector(kDisjunction
, kDisjunctionSizes
, 4u, &tests
);
697 MatchAndCheck(tests
, keys::kResponseHeadersKey
, stage
, url_request
.get(),
701 // 3.a. -- This should pass.
702 const std::string kNonExistent
[] = {
703 keys::kNameEqualsKey
, "Non-existing",
704 keys::kValueEqualsKey
, "void"
706 const size_t kNonExistentSizes
[] = { arraysize(kNonExistent
) };
707 GetArrayAsVector(kNonExistent
, kNonExistentSizes
, 1u, &tests
);
708 MatchAndCheck(tests
, keys::kExcludeResponseHeadersKey
, stage
,
709 url_request
.get(), &result
);
712 // 3.b. -- This should fail.
713 const std::string kExisting
[] = {
714 keys::kNameEqualsKey
, "custom-header-b",
715 keys::kValueEqualsKey
, "valueB"
717 const size_t kExistingSize
[] = { arraysize(kExisting
) };
718 GetArrayAsVector(kExisting
, kExistingSize
, 1u, &tests
);
719 MatchAndCheck(tests
, keys::kExcludeResponseHeadersKey
, stage
,
720 url_request
.get(), &result
);
721 EXPECT_FALSE(result
);
725 } // namespace extensions