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
));
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
));
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(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
;
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
,
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
,
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
))
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
);
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
,
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
,
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
,
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
) {
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
)));
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 }
349 // results in out == { {&"a", &"b"}, {}, {&"c", &"d", &"e", &"f"} }
350 void GetArrayAsVector(const std::string array
[],
351 const size_t sizes
[],
353 std::vector
< std::vector
<const std::string
*> >* out
) {
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
]));
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
);
392 case base::Value::TYPE_LIST
: // Just append to the list.
393 CHECK(entry
->GetAsList(&list
));
394 list
->Append(new base::StringValue(*value
));
397 NOTREACHED(); // We never put other Values here.
398 return scoped_ptr
<base::DictionaryValue
>();
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
,
415 net::URLRequest
* url_request
,
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());
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()));
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
;
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).
471 tests
, keys::kRequestHeadersKey
, stage
, url_request
.get(), &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(),
490 EXPECT_FALSE(result
);
491 // Negative filter, passing (disjunction of tests).
492 MatchAndCheck(tests
, keys::kExcludeRequestHeadersKey
, stage
,
493 url_request
.get(), &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(),
501 EXPECT_FALSE(result
);
502 // Negative filter, passing (no test to fail).
503 MatchAndCheck(tests
, keys::kExcludeRequestHeadersKey
, stage
,
504 url_request
.get(), &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(),
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
546 // in the response, but does not include "Non-existing: void".
548 std::vector
< std::vector
<const std::string
*> > tests
;
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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
);
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
);
717 } // namespace extensions