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