This source file includes following definitions.
- TestDataPath
- TEST
- TEST
- TEST
- TEST
- TEST
- GetArrayAsVector
- GetDictionaryFromArray
- MatchAndCheck
- TEST
- TEST
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
#include "content/public/browser/resource_request_info.h"
#include "net/base/request_priority.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::DictionaryValue;
using base::FundamentalValue;
using base::ListValue;
using base::StringValue;
using base::Value;
namespace extensions {
namespace keys = declarative_webrequest_constants;
namespace {
const char kUnknownConditionName[] = "unknownType";
base::FilePath TestDataPath(base::StringPiece relative_to_src) {
base::FilePath src_dir;
CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
return src_dir.AppendASCII(relative_to_src);
}
TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) {
base::MessageLoopForIO message_loop;
std::string error;
scoped_refptr<const WebRequestConditionAttribute> result;
base::StringValue string_value("main_frame");
base::ListValue resource_types;
resource_types.Append(new base::StringValue("main_frame"));
error.clear();
result = WebRequestConditionAttribute::Create(
kUnknownConditionName, &resource_types, &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
error.clear();
result = WebRequestConditionAttribute::Create(
keys::kResourceTypeKey, &string_value, &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
error.clear();
result = WebRequestConditionAttribute::Create(
keys::kContentTypeKey, &string_value, &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
error.clear();
result = WebRequestConditionAttribute::Create(
keys::kResourceTypeKey, &resource_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
EXPECT_EQ(WebRequestConditionAttribute::CONDITION_RESOURCE_TYPE,
result->GetType());
EXPECT_EQ(std::string(keys::kResourceTypeKey), result->GetName());
}
TEST(WebRequestConditionAttributeTest, ResourceType) {
base::MessageLoopForIO message_loop;
std::string error;
base::ListValue resource_types;
resource_types.Append(new base::StringValue("sub_frame"));
scoped_refptr<const WebRequestConditionAttribute> attribute =
WebRequestConditionAttribute::Create(
keys::kResourceTypeKey, &resource_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute.get());
EXPECT_EQ(std::string(keys::kResourceTypeKey), attribute->GetName());
net::TestURLRequestContext context;
net::TestURLRequest url_request_ok(
GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, &context);
content::ResourceRequestInfo::AllocateForTesting(
&url_request_ok, ResourceType::SUB_FRAME, NULL, -1, -1, -1, false);
EXPECT_TRUE(attribute->IsFulfilled(WebRequestData(&url_request_ok,
ON_BEFORE_REQUEST)));
net::TestURLRequest url_request_fail(
GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, &context);
content::ResourceRequestInfo::AllocateForTesting(
&url_request_fail, ResourceType::MAIN_FRAME, NULL, -1, -1, -1, false);
EXPECT_FALSE(attribute->IsFulfilled(WebRequestData(&url_request_fail,
ON_BEFORE_REQUEST)));
}
TEST(WebRequestConditionAttributeTest, ContentType) {
base::MessageLoopForIO message_loop;
std::string error;
scoped_refptr<const WebRequestConditionAttribute> result;
net::test_server::EmbeddedTestServer test_server;
test_server.ServeFilesFromDirectory(TestDataPath(
"chrome/test/data/extensions/api_test/webrequest/declarative"));
ASSERT_TRUE(test_server.InitializeAndWaitUntilReady());
net::TestURLRequestContext context;
net::TestDelegate delegate;
net::TestURLRequest url_request(test_server.GetURL("/headers.html"),
net::DEFAULT_PRIORITY,
&delegate,
&context);
url_request.Start();
base::MessageLoop::current()->Run();
base::ListValue content_types;
content_types.Append(new base::StringValue("text/plain"));
scoped_refptr<const WebRequestConditionAttribute> attribute_include =
WebRequestConditionAttribute::Create(
keys::kContentTypeKey, &content_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_include.get());
EXPECT_FALSE(attribute_include->IsFulfilled(
WebRequestData(&url_request, ON_BEFORE_REQUEST,
url_request.response_headers())));
EXPECT_TRUE(attribute_include->IsFulfilled(
WebRequestData(&url_request, ON_HEADERS_RECEIVED,
url_request.response_headers())));
EXPECT_EQ(std::string(keys::kContentTypeKey), attribute_include->GetName());
scoped_refptr<const WebRequestConditionAttribute> attribute_exclude =
WebRequestConditionAttribute::Create(
keys::kExcludeContentTypeKey, &content_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_exclude.get());
EXPECT_FALSE(attribute_exclude->IsFulfilled(
WebRequestData(&url_request, ON_HEADERS_RECEIVED,
url_request.response_headers())));
content_types.Clear();
content_types.Append(new base::StringValue("something/invalid"));
scoped_refptr<const WebRequestConditionAttribute> attribute_unincluded =
WebRequestConditionAttribute::Create(
keys::kContentTypeKey, &content_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_unincluded.get());
EXPECT_FALSE(attribute_unincluded->IsFulfilled(
WebRequestData(&url_request, ON_HEADERS_RECEIVED,
url_request.response_headers())));
scoped_refptr<const WebRequestConditionAttribute> attribute_unexcluded =
WebRequestConditionAttribute::Create(
keys::kExcludeContentTypeKey, &content_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_unexcluded.get());
EXPECT_TRUE(attribute_unexcluded->IsFulfilled(
WebRequestData(&url_request, ON_HEADERS_RECEIVED,
url_request.response_headers())));
EXPECT_EQ(std::string(keys::kExcludeContentTypeKey),
attribute_unexcluded->GetName());
}
TEST(WebRequestConditionAttributeTest, ThirdParty) {
base::MessageLoopForIO message_loop;
std::string error;
const FundamentalValue value_true(true);
scoped_refptr<const WebRequestConditionAttribute> third_party_attribute =
WebRequestConditionAttribute::Create(keys::kThirdPartyKey,
&value_true,
&error);
ASSERT_EQ("", error);
ASSERT_TRUE(third_party_attribute.get());
EXPECT_EQ(std::string(keys::kThirdPartyKey),
third_party_attribute->GetName());
const FundamentalValue value_false(false);
scoped_refptr<const WebRequestConditionAttribute> first_party_attribute =
WebRequestConditionAttribute::Create(keys::kThirdPartyKey,
&value_false,
&error);
ASSERT_EQ("", error);
ASSERT_TRUE(first_party_attribute.get());
EXPECT_EQ(std::string(keys::kThirdPartyKey),
first_party_attribute->GetName());
const GURL url_empty;
const GURL url_a("http://a.com");
const GURL url_b("http://b.com");
net::TestURLRequestContext context;
net::TestDelegate delegate;
net::TestURLRequest url_request(
url_a, net::DEFAULT_PRIORITY, &delegate, &context);
for (unsigned int i = 1; i <= kLastActiveStage; i <<= 1) {
if (!(kActiveStages & i))
continue;
const RequestStage stage = static_cast<RequestStage>(i);
url_request.set_first_party_for_cookies(url_empty);
EXPECT_FALSE(third_party_attribute->IsFulfilled(WebRequestData(&url_request,
stage)));
EXPECT_TRUE(first_party_attribute->IsFulfilled(WebRequestData(&url_request,
stage)));
url_request.set_first_party_for_cookies(url_b);
EXPECT_TRUE(third_party_attribute->IsFulfilled(WebRequestData(&url_request,
stage)));
EXPECT_FALSE(first_party_attribute->IsFulfilled(WebRequestData(&url_request,
stage)));
url_request.set_first_party_for_cookies(url_a);
EXPECT_FALSE(third_party_attribute->IsFulfilled(WebRequestData(&url_request,
stage)));
EXPECT_TRUE(first_party_attribute->IsFulfilled(WebRequestData(&url_request,
stage)));
}
}
TEST(WebRequestConditionAttributeTest, Stages) {
base::MessageLoopForIO message_loop;
typedef std::pair<RequestStage, const char*> StageNamePair;
static const StageNamePair active_stages[] = {
StageNamePair(ON_BEFORE_REQUEST, keys::kOnBeforeRequestEnum),
StageNamePair(ON_BEFORE_SEND_HEADERS, keys::kOnBeforeSendHeadersEnum),
StageNamePair(ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEnum),
StageNamePair(ON_AUTH_REQUIRED, keys::kOnAuthRequiredEnum)
};
unsigned int covered_stages = 0;
for (size_t i = 0; i < arraysize(active_stages); ++i)
covered_stages |= active_stages[i].first;
EXPECT_EQ(kActiveStages, covered_stages);
std::string error;
base::ListValue empty_list;
scoped_refptr<const WebRequestConditionAttribute> empty_attribute =
WebRequestConditionAttribute::Create(keys::kStagesKey,
&empty_list,
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(empty_attribute.get());
EXPECT_EQ(std::string(keys::kStagesKey), empty_attribute->GetName());
base::ListValue all_stages;
for (size_t i = 0; i < arraysize(active_stages); ++i)
all_stages.AppendString(active_stages[i].second);
scoped_refptr<const WebRequestConditionAttribute> attribute_with_all =
WebRequestConditionAttribute::Create(keys::kStagesKey,
&all_stages,
&error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_with_all.get());
EXPECT_EQ(std::string(keys::kStagesKey), attribute_with_all->GetName());
std::vector<scoped_refptr<const WebRequestConditionAttribute> >
one_stage_attributes;
for (size_t i = 0; i < arraysize(active_stages); ++i) {
base::ListValue single_stage_list;
single_stage_list.AppendString(active_stages[i].second);
one_stage_attributes.push_back(
WebRequestConditionAttribute::Create(keys::kStagesKey,
&single_stage_list,
&error));
EXPECT_EQ("", error);
ASSERT_TRUE(one_stage_attributes.back().get() != NULL);
}
const GURL url_empty;
net::TestURLRequestContext context;
net::TestDelegate delegate;
net::TestURLRequest url_request(
url_empty, net::DEFAULT_PRIORITY, &delegate, &context);
for (size_t i = 0; i < arraysize(active_stages); ++i) {
EXPECT_FALSE(empty_attribute->IsFulfilled(
WebRequestData(&url_request, active_stages[i].first)));
for (size_t j = 0; j < one_stage_attributes.size(); ++j) {
EXPECT_EQ(i == j,
one_stage_attributes[j]->IsFulfilled(
WebRequestData(&url_request, active_stages[i].first)));
}
EXPECT_TRUE(attribute_with_all->IsFulfilled(
WebRequestData(&url_request, active_stages[i].first)));
}
}
namespace {
void GetArrayAsVector(const std::string array[],
const size_t sizes[],
const size_t size,
std::vector< std::vector<const std::string*> >* out) {
out->clear();
size_t next = 0;
for (size_t i = 0; i < size; ++i) {
out->push_back(std::vector<const std::string*>());
for (size_t j = next; j < next + sizes[i]; ++j) {
out->back().push_back(&(array[j]));
}
next += sizes[i];
}
}
scoped_ptr<base::DictionaryValue> GetDictionaryFromArray(
const std::vector<const std::string*>& array) {
const size_t length = array.size();
CHECK(length % 2 == 0);
scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
for (size_t i = 0; i < length; i += 2) {
const std::string* name = array[i];
const std::string* value = array[i+1];
if (dictionary->HasKey(*name)) {
base::Value* entry = NULL;
scoped_ptr<base::Value> entry_owned;
base::ListValue* list = NULL;
if (!dictionary->GetWithoutPathExpansion(*name, &entry))
return scoped_ptr<base::DictionaryValue>();
switch (entry->GetType()) {
case base::Value::TYPE_STRING:
list = new base::ListValue;
dictionary->RemoveWithoutPathExpansion(*name, &entry_owned);
list->Append(entry_owned.release());
list->Append(new base::StringValue(*value));
dictionary->SetWithoutPathExpansion(*name, list);
break;
case base::Value::TYPE_LIST:
CHECK(entry->GetAsList(&list));
list->Append(new base::StringValue(*value));
break;
default:
NOTREACHED();
return scoped_ptr<base::DictionaryValue>();
}
} else {
dictionary->SetString(*name, *value);
}
}
return dictionary.Pass();
}
void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests,
const std::string& key,
RequestStage stage,
net::URLRequest* url_request,
bool* result) {
base::ListValue contains_headers;
for (size_t i = 0; i < tests.size(); ++i) {
scoped_ptr<base::DictionaryValue> temp(GetDictionaryFromArray(tests[i]));
ASSERT_TRUE(temp.get());
contains_headers.Append(temp.release());
}
std::string error;
scoped_refptr<const WebRequestConditionAttribute> attribute =
WebRequestConditionAttribute::Create(key, &contains_headers, &error);
ASSERT_EQ("", error);
ASSERT_TRUE(attribute.get());
EXPECT_EQ(key, attribute->GetName());
*result = attribute->IsFulfilled(WebRequestData(
url_request, stage, url_request->response_headers()));
}
}
TEST(WebRequestConditionAttributeTest, RequestHeaders) {
base::MessageLoopForIO message_loop;
net::TestURLRequestContext context;
net::TestDelegate delegate;
net::TestURLRequest url_request(GURL("http://example.com"),
net::DEFAULT_PRIORITY,
&delegate,
&context);
url_request.SetExtraRequestHeaderByName(
"Custom-header", "custom/value", true );
url_request.Start();
base::MessageLoop::current()->Run();
std::vector<std::vector<const std::string*> > tests;
bool result = false;
const RequestStage stage = ON_BEFORE_SEND_HEADERS;
const std::string kPassingCondition[] = {
keys::kNameContainsKey, "CuStOm",
keys::kNameEqualsKey, "custom-header",
keys::kValueSuffixKey, "alue",
keys::kValuePrefixKey, "custom/value"
};
const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) };
GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
MatchAndCheck(
tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
const std::string kFailCondition[] = {
keys::kNameSuffixKey, "Custom",
keys::kNameEqualsKey, "ustom-valu",
keys::kValuePrefixKey, "custom ",
keys::kValueContainsKey, " value"
};
const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
MatchAndCheck(
tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
GetArrayAsVector(NULL, NULL, 0u, &tests);
MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
MatchAndCheck(
tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const size_t kEmptyConjunctionSizes[] = { 0u };
GetArrayAsVector(NULL, kEmptyConjunctionSizes, 1u, &tests);
MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
MatchAndCheck(
tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
}
TEST(WebRequestConditionAttributeTest, ResponseHeaders) {
base::MessageLoopForIO message_loop;
net::test_server::EmbeddedTestServer test_server;
test_server.ServeFilesFromDirectory(TestDataPath(
"chrome/test/data/extensions/api_test/webrequest/declarative"));
ASSERT_TRUE(test_server.InitializeAndWaitUntilReady());
net::TestURLRequestContext context;
net::TestDelegate delegate;
net::TestURLRequest url_request(test_server.GetURL("/headers.html"),
net::DEFAULT_PRIORITY,
&delegate,
&context);
url_request.Start();
base::MessageLoop::current()->Run();
std::vector< std::vector<const std::string*> > tests;
bool result;
const RequestStage stage = ON_HEADERS_RECEIVED;
const std::string kPassingCondition[] = {
keys::kNamePrefixKey, "Custom",
keys::kNameSuffixKey, "m-header",
keys::kValueContainsKey, "alu",
keys::kValueEqualsKey, "custom/value"
};
const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) };
GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kFailCondition[] = {
keys::kNamePrefixKey, " Custom",
keys::kNameContainsKey, " -",
keys::kValueSuffixKey, "alu",
keys::kValueEqualsKey, "custom"
};
const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
const std::string kMixingCondition[] = {
keys::kNameSuffixKey, "Header-B",
keys::kValueEqualsKey, "custom/value"
};
const size_t kMixingConditionSizes[] = { arraysize(kMixingCondition) };
GetArrayAsVector(kMixingCondition, kMixingConditionSizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
const std::string kMoreValues1[] = {
keys::kNameEqualsKey, "Custom-header-b",
keys::kValueEqualsKey, "valueA"
};
const size_t kMoreValues1Sizes[] = { arraysize(kMoreValues1) };
GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kMoreValues2[] = {
keys::kNameEqualsKey, "Custom-header-b",
keys::kValueEqualsKey, "valueB"
};
const size_t kMoreValues2Sizes[] = { arraysize(kMoreValues2) };
GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kConflict[] = {
keys::kNameSuffixKey, "Header",
keys::kNameContainsKey, "Header-B"
};
const size_t kNoConflictSizes[] = { 2u, 2u };
GetArrayAsVector(kConflict, kNoConflictSizes, 2u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const size_t kConflictSizes[] = { arraysize(kConflict) };
GetArrayAsVector(kConflict, kConflictSizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
const std::string kComma[] = {
keys::kNameSuffixKey, "Header-C",
keys::kValueEqualsKey, "valueC, valueD"
};
const size_t kCommaSizes[] = { arraysize(kComma) };
GetArrayAsVector(kComma, kCommaSizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kEmpty[] = {
keys::kNameEqualsKey, "custom-header-d",
keys::kValueEqualsKey, ""
};
const size_t kEmptySizes[] = { arraysize(kEmpty) };
GetArrayAsVector(kEmpty, kEmptySizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kLowercase[] = {
keys::kNameEqualsKey, "Custom-header-b",
keys::kValuePrefixKey, "valueb",
keys::kNameEqualsKey, "Custom-header-b",
keys::kValueSuffixKey, "valueb",
keys::kNameEqualsKey, "Custom-header-b",
keys::kValueContainsKey, "valueb",
keys::kNameEqualsKey, "Custom-header-b",
keys::kValueEqualsKey, "valueb"
};
const size_t kLowercaseSizes[] = { 4u, 4u, 4u, 4u };
GetArrayAsVector(kLowercase, kLowercaseSizes, 4u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
const std::string kUppercase[] = {
keys::kNamePrefixKey, "CUSTOM-HEADER-B",
keys::kNameSuffixKey, "CUSTOM-HEADER-B",
keys::kNameEqualsKey, "CUSTOM-HEADER-B",
keys::kNameContainsKey, "CUSTOM-HEADER-B"
};
const size_t kUppercaseSizes[] = { arraysize(kUppercase) };
GetArrayAsVector(kUppercase, kUppercaseSizes, 1u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kDisjunction[] = {
keys::kNamePrefixKey, "Non-existing",
keys::kNameSuffixKey, "Non-existing",
keys::kValueEqualsKey, "void",
keys::kValueContainsKey, "alu"
};
const size_t kDisjunctionSizes[] = { 2u, 2u, 2u, 2u };
GetArrayAsVector(kDisjunction, kDisjunctionSizes, 4u, &tests);
MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kNonExistent[] = {
keys::kNameEqualsKey, "Non-existing",
keys::kValueEqualsKey, "void"
};
const size_t kNonExistentSizes[] = { arraysize(kNonExistent) };
GetArrayAsVector(kNonExistent, kNonExistentSizes, 1u, &tests);
MatchAndCheck(
tests, keys::kExcludeResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kExisting[] = {
keys::kNameEqualsKey, "custom-header-b",
keys::kValueEqualsKey, "valueB"
};
const size_t kExistingSize[] = { arraysize(kExisting) };
GetArrayAsVector(kExisting, kExistingSize, 1u, &tests);
MatchAndCheck(
tests, keys::kExcludeResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
}
}
}