summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc114
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h39
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc115
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc2
-rw-r--r--chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h2
-rw-r--r--chrome/common/extensions/api/declarative_web_request.json16
-rw-r--r--chrome/test/data/extensions/api_test/webrequest/test_declarative.js33
7 files changed, 286 insertions, 35 deletions
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
index 554bc5f..84c2b66 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -54,6 +54,8 @@ bool WebRequestConditionAttribute::IsKnownType(
return
WebRequestConditionAttributeResourceType::IsMatchingType(instance_type) ||
WebRequestConditionAttributeContentType::IsMatchingType(instance_type) ||
+ WebRequestConditionAttributeRequestHeaders::IsMatchingType(
+ instance_type) ||
WebRequestConditionAttributeResponseHeaders::IsMatchingType(
instance_type) ||
WebRequestConditionAttributeThirdParty::IsMatchingType(instance_type);
@@ -70,6 +72,10 @@ WebRequestConditionAttribute::Create(
return WebRequestConditionAttributeResourceType::Create(name, value, error);
} else if (WebRequestConditionAttributeContentType::IsMatchingType(name)) {
return WebRequestConditionAttributeContentType::Create(name, value, error);
+ } else if (WebRequestConditionAttributeRequestHeaders::IsMatchingType(
+ name)) {
+ return WebRequestConditionAttributeRequestHeaders::Create(
+ name, value, error);
} else if (WebRequestConditionAttributeResponseHeaders::IsMatchingType(
name)) {
return WebRequestConditionAttributeResponseHeaders::Create(
@@ -490,14 +496,103 @@ bool HeaderMatcher::HeaderMatchTest::Matches(const std::string& name,
}
//
+// WebRequestConditionAttributeRequestHeaders
+//
+
+WebRequestConditionAttributeRequestHeaders::
+WebRequestConditionAttributeRequestHeaders(
+ scoped_ptr<const HeaderMatcher> header_matcher,
+ bool positive)
+ : header_matcher_(header_matcher.Pass()),
+ positive_(positive) {}
+
+WebRequestConditionAttributeRequestHeaders::
+~WebRequestConditionAttributeRequestHeaders() {}
+
+// static
+bool WebRequestConditionAttributeRequestHeaders::IsMatchingType(
+ const std::string& instance_type) {
+ return instance_type == keys::kRequestHeadersKey ||
+ instance_type == keys::kExcludeRequestHeadersKey;
+}
+
+namespace {
+
+scoped_ptr<const HeaderMatcher> PrepareHeaderMatcher(
+ const std::string& name,
+ const base::Value* value,
+ std::string* error) {
+ const ListValue* value_as_list = NULL;
+ if (!value->GetAsList(&value_as_list)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ return scoped_ptr<const HeaderMatcher>(NULL);
+ }
+
+ scoped_ptr<const HeaderMatcher> header_matcher(
+ HeaderMatcher::Create(value_as_list));
+ if (header_matcher.get() == NULL)
+ *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ return header_matcher.Pass();
+}
+
+} // namespace
+
+// static
+scoped_ptr<WebRequestConditionAttribute>
+WebRequestConditionAttributeRequestHeaders::Create(
+ const std::string& name,
+ const base::Value* value,
+ std::string* error) {
+ DCHECK(IsMatchingType(name));
+
+ scoped_ptr<const HeaderMatcher> header_matcher(
+ PrepareHeaderMatcher(name, value, error));
+ if (header_matcher.get() == NULL)
+ return scoped_ptr<WebRequestConditionAttribute>(NULL);
+
+ return scoped_ptr<WebRequestConditionAttribute>(
+ new WebRequestConditionAttributeRequestHeaders(
+ header_matcher.Pass(), name == keys::kRequestHeadersKey));
+}
+
+int WebRequestConditionAttributeRequestHeaders::GetStages() const {
+ // Currently we only allow matching against headers in the before-send-headers
+ // stage. The headers are accessible in other stages as well, but before
+ // allowing to match against them in further stages, we should consider
+ // caching the match result.
+ return ON_BEFORE_SEND_HEADERS;
+}
+
+bool WebRequestConditionAttributeRequestHeaders::IsFulfilled(
+ const WebRequestRule::RequestData& request_data) const {
+ if (!(request_data.stage & GetStages()))
+ return false;
+
+ const net::HttpRequestHeaders& headers =
+ request_data.request->extra_request_headers();
+
+ bool passed = false; // Did some header pass TestNameValue?
+ net::HttpRequestHeaders::Iterator it(headers);
+ while (!passed && it.GetNext())
+ passed |= header_matcher_->TestNameValue(it.name(), it.value());
+
+ return (positive_ ? passed : !passed);
+}
+
+WebRequestConditionAttribute::Type
+WebRequestConditionAttributeRequestHeaders::GetType() const {
+ return CONDITION_REQUEST_HEADERS;
+}
+
+//
// WebRequestConditionAttributeResponseHeaders
//
WebRequestConditionAttributeResponseHeaders::
WebRequestConditionAttributeResponseHeaders(
- scoped_ptr<const HeaderMatcher>* header_matcher,
+ scoped_ptr<const HeaderMatcher> header_matcher,
bool positive)
- : header_matcher_(header_matcher->Pass()),
+ : header_matcher_(header_matcher.Pass()),
positive_(positive) {}
WebRequestConditionAttributeResponseHeaders::
@@ -518,23 +613,14 @@ WebRequestConditionAttributeResponseHeaders::Create(
std::string* error) {
DCHECK(IsMatchingType(name));
- const ListValue* value_as_list = NULL;
- if (!value->GetAsList(&value_as_list)) {
- *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
- return scoped_ptr<WebRequestConditionAttribute>(NULL);
- }
-
scoped_ptr<const HeaderMatcher> header_matcher(
- HeaderMatcher::Create(value_as_list));
- if (header_matcher.get() == NULL) {
- *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue, name);
+ PrepareHeaderMatcher(name, value, error));
+ if (header_matcher.get() == NULL)
return scoped_ptr<WebRequestConditionAttribute>(NULL);
- }
- const bool positive = name == keys::kResponseHeadersKey;
return scoped_ptr<WebRequestConditionAttribute>(
new WebRequestConditionAttributeResponseHeaders(
- &header_matcher, positive));
+ header_matcher.Pass(), name == keys::kResponseHeadersKey));
}
int WebRequestConditionAttributeResponseHeaders::GetStages() const {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h
index 00f5eed..bde449c 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h
@@ -37,7 +37,8 @@ class WebRequestConditionAttribute {
CONDITION_RESOURCE_TYPE,
CONDITION_CONTENT_TYPE,
CONDITION_RESPONSE_HEADERS,
- CONDITION_THIRD_PARTY
+ CONDITION_THIRD_PARTY,
+ CONDITION_REQUEST_HEADERS
};
WebRequestConditionAttribute();
@@ -139,6 +140,40 @@ class WebRequestConditionAttributeContentType
DISALLOW_COPY_AND_ASSIGN(WebRequestConditionAttributeContentType);
};
+// Condition attribute for matching against request headers. Uses HeaderMatcher
+// to handle the actual tests, in connection with a boolean positiveness
+// flag. If that flag is set to true, then IsFulfilled() returns true iff
+// |header_matcher_| matches at least one header. Otherwise IsFulfilled()
+// returns true iff the |header_matcher_| matches no header.
+class WebRequestConditionAttributeRequestHeaders
+ : public WebRequestConditionAttribute {
+ public:
+ virtual ~WebRequestConditionAttributeRequestHeaders();
+
+ static bool IsMatchingType(const std::string& instance_type);
+
+ // Factory method, see WebRequestConditionAttribute::Create.
+ static scoped_ptr<WebRequestConditionAttribute> Create(
+ const std::string& name,
+ const base::Value* value,
+ std::string* error);
+
+ // Implementation of WebRequestConditionAttribute:
+ virtual int GetStages() const OVERRIDE;
+ virtual bool IsFulfilled(
+ const WebRequestRule::RequestData& request_data) const OVERRIDE;
+ virtual Type GetType() const OVERRIDE;
+
+ private:
+ WebRequestConditionAttributeRequestHeaders(
+ scoped_ptr<const HeaderMatcher> header_matcher, bool positive);
+
+ const scoped_ptr<const HeaderMatcher> header_matcher_;
+ const bool positive_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebRequestConditionAttributeRequestHeaders);
+};
+
// Condition attribute for matching against response headers. Uses HeaderMatcher
// to handle the actual tests, in connection with a boolean positiveness
// flag. If that flag is set to true, then IsFulfilled() returns true iff
@@ -165,7 +200,7 @@ class WebRequestConditionAttributeResponseHeaders
private:
WebRequestConditionAttributeResponseHeaders(
- scoped_ptr<const HeaderMatcher>* header_matcher, bool positive);
+ scoped_ptr<const HeaderMatcher> header_matcher, bool positive);
const scoped_ptr<const HeaderMatcher> header_matcher_;
const bool positive_;
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
index 56e7005..6366b9e 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
@@ -298,6 +298,7 @@ scoped_ptr<DictionaryValue> GetDictionaryFromArray(
// doesNotContainHeaders.
void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests,
const std::string& key,
+ RequestStage stage,
net::URLRequest* url_request,
bool* result) {
ListValue contains_headers;
@@ -314,16 +315,94 @@ void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests,
ASSERT_TRUE(attribute.get() != NULL);
*result = attribute->IsFulfilled(WebRequestRule::RequestData(
- url_request, ON_HEADERS_RECEIVED, url_request->response_headers()));
+ url_request, stage, url_request->response_headers()));
}
} // namespace
+// Here we test WebRequestConditionAttributeRequestHeaders for matching
+// correctly against request headers. This test is not as extensive as
+// "ResponseHeaders" (below), because the header-matching code is shared
+// by both types of condition attributes, so it is enough to test it once.
+TEST(WebRequestConditionAttributeTest, RequestHeaders) {
+ // Necessary for TestURLRequest.
+ MessageLoop message_loop(MessageLoop::TYPE_IO);
+
+ TestURLRequestContext context;
+ TestDelegate delegate;
+ TestURLRequest url_request(GURL("http://example.com"), // Dummy URL.
+ &delegate, &context);
+ url_request.SetExtraRequestHeaderByName(
+ "Custom-header", "custom/value", true /* overwrite */);
+ url_request.Start();
+ MessageLoop::current()->Run();
+
+ std::vector<std::vector<const std::string*> > tests;
+ bool result = false;
+
+ const RequestStage stage = ON_BEFORE_SEND_HEADERS;
+
+ // First set of test data -- passing conjunction.
+ const std::string kPassingCondition[] = {
+ keys::kNameContainsKey, "CuStOm", // Header names are case insensitive.
+ keys::kNameEqualsKey, "custom-header",
+ keys::kValueSuffixKey, "alue",
+ keys::kValuePrefixKey, "custom/value"
+ };
+ const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) };
+ GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
+ // Positive filter, passing (conjunction of tests).
+ MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_TRUE(result);
+ // Negative filter, failing (conjunction of tests).
+ MatchAndCheck(
+ tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_FALSE(result);
+
+ // Second set of test data -- failing disjunction.
+ const std::string kFailCondition[] = {
+ keys::kNameSuffixKey, "Custom", // Test 1.
+ keys::kNameEqualsKey, "ustom-valu", // Test 2.
+ keys::kValuePrefixKey, "custom ", // Test 3.
+ keys::kValueContainsKey, " value" // Test 4.
+ };
+ const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
+ GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
+ // Positive filter, failing (disjunction of tests).
+ MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_FALSE(result);
+ // Negative filter, passing (disjunction of tests).
+ MatchAndCheck(
+ tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_TRUE(result);
+
+ // Third set of test data, corner case -- empty disjunction.
+ GetArrayAsVector(NULL, NULL, 0u, &tests);
+ // Positive filter, failing (no test to pass).
+ MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_FALSE(result);
+ // Negative filter, passing (no test to fail).
+ MatchAndCheck(
+ tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_TRUE(result);
+
+ // Fourth set of test data, corner case -- empty conjunction.
+ const size_t kEmptyConjunctionSizes[] = { 0u };
+ GetArrayAsVector(NULL, kEmptyConjunctionSizes, 1u, &tests);
+ // Positive filter, passing (trivial test).
+ MatchAndCheck(tests, keys::kRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_TRUE(result);
+ // Negative filter, failing.
+ MatchAndCheck(
+ tests, keys::kExcludeRequestHeadersKey, stage, &url_request, &result);
+ EXPECT_FALSE(result);
+}
+
// Here we test WebRequestConditionAttributeResponseHeaders for:
// 1. Correct implementation of prefix/suffix/contains/equals matching.
// 2. Performing logical disjunction (||) between multiple specifications.
// 3. Negating the match in case of 'doesNotContainHeaders'.
-TEST(WebRequestConditionAttributeTest, Headers) {
+TEST(WebRequestConditionAttributeTest, ResponseHeaders) {
// Necessary for TestURLRequest.
MessageLoop message_loop(MessageLoop::TYPE_IO);
@@ -352,6 +431,8 @@ TEST(WebRequestConditionAttributeTest, Headers) {
std::vector< std::vector<const std::string*> > tests;
bool result;
+ const RequestStage stage = ON_HEADERS_RECEIVED;
+
// 1.a. -- All these tests should pass.
const std::string kPassingCondition[] = {
keys::kNamePrefixKey, "Custom",
@@ -361,7 +442,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) };
GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 1.b. -- None of the following tests in the discjunction should pass.
@@ -373,7 +454,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
// 1.c. -- This should fail (mixing name and value from different headers)
@@ -383,7 +464,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kMixingConditionSizes[] = { arraysize(kMixingCondition) };
GetArrayAsVector(kMixingCondition, kMixingConditionSizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
// 1.d. -- Test handling multiple values for one header (both should pass).
@@ -393,7 +474,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kMoreValues1Sizes[] = { arraysize(kMoreValues1) };
GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
const std::string kMoreValues2[] = {
keys::kNameEqualsKey, "Custom-header-b",
@@ -401,7 +482,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kMoreValues2Sizes[] = { arraysize(kMoreValues2) };
GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 1.e. -- This should fail as conjunction but pass as disjunction.
@@ -412,12 +493,12 @@ TEST(WebRequestConditionAttributeTest, Headers) {
// First disjunction, no conflict.
const size_t kNoConflictSizes[] = { 2u, 2u };
GetArrayAsVector(kConflict, kNoConflictSizes, 2u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// Then conjunction, conflict.
const size_t kConflictSizes[] = { arraysize(kConflict) };
GetArrayAsVector(kConflict, kConflictSizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
// 1.f. -- This should pass, checking for correct treatment of ',' in values.
@@ -427,7 +508,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kCommaSizes[] = { arraysize(kComma) };
GetArrayAsVector(kComma, kCommaSizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 1.g. -- This should pass, empty values are values as well.
@@ -437,7 +518,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kEmptySizes[] = { arraysize(kEmpty) };
GetArrayAsVector(kEmpty, kEmptySizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 1.h. -- Values are case-sensitive, this should fail.
@@ -453,7 +534,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kLowercaseSizes[] = { 4u, 4u, 4u, 4u }; // As disjunction.
GetArrayAsVector(kLowercase, kLowercaseSizes, 4u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
// 1.i. -- Names are case-insensitive, this should pass.
@@ -465,7 +546,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kUppercaseSizes[] = { arraysize(kUppercase) }; // Conjunction.
GetArrayAsVector(kUppercase, kUppercaseSizes, 1u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 2.a. -- This should pass as disjunction, because one of the tests passes.
@@ -477,7 +558,7 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kDisjunctionSizes[] = { 2u, 2u, 2u, 2u };
GetArrayAsVector(kDisjunction, kDisjunctionSizes, 4u, &tests);
- MatchAndCheck(tests, keys::kResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(tests, keys::kResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 3.a. -- This should pass.
@@ -487,7 +568,8 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kNonExistentSizes[] = { arraysize(kNonExistent) };
GetArrayAsVector(kNonExistent, kNonExistentSizes, 1u, &tests);
- MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(
+ tests, keys::kExcludeResponseHeadersKey, stage, &url_request, &result);
EXPECT_TRUE(result);
// 3.b. -- This should fail.
@@ -497,7 +579,8 @@ TEST(WebRequestConditionAttributeTest, Headers) {
};
const size_t kExistingSize[] = { arraysize(kExisting) };
GetArrayAsVector(kExisting, kExistingSize, 1u, &tests);
- MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, &url_request, &result);
+ MatchAndCheck(
+ tests, keys::kExcludeResponseHeadersKey, stage, &url_request, &result);
EXPECT_FALSE(result);
}
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc
index c1560f0..2f2850c 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc
@@ -18,6 +18,7 @@ const char kContentTypeKey[] = "contentType";
const char kDirectionKey[] = "direction";
const char kDomainKey[] = "domain";
const char kExcludeContentTypeKey[] = "excludeContentType";
+const char kExcludeRequestHeadersKey[] = "excludeRequestHeaders";
const char kExcludeResponseHeadersKey[] = "excludeResponseHeaders";
const char kExpiresKey[] = "expires";
const char kFilterKey[] ="filter";
@@ -34,6 +35,7 @@ const char kNamePrefixKey[] = "namePrefix";
const char kNameSuffixKey[] = "nameSuffix";
const char kPathKey[] = "path";
const char kRedirectUrlKey[] = "redirectUrl";
+const char kRequestHeadersKey[] = "requestHeaders";
const char kResourceTypeKey[] = "resourceType";
const char kResponseHeadersKey[] = "responseHeaders";
const char kSecureKey[] = "secure";
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h
index 1bc0ef6..364a651 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h
@@ -21,6 +21,7 @@ extern const char kContentTypeKey[];
extern const char kDirectionKey[];
extern const char kDomainKey[];
extern const char kExcludeContentTypeKey[];
+extern const char kExcludeRequestHeadersKey[];
extern const char kExcludeResponseHeadersKey[];
extern const char kExpiresKey[];
extern const char kFilterKey[];
@@ -37,6 +38,7 @@ extern const char kNamePrefixKey[];
extern const char kNameSuffixKey[];
extern const char kPathKey[];
extern const char kRedirectUrlKey[];
+extern const char kRequestHeadersKey[];
extern const char kResourceTypeKey[];
extern const char kResponseHeadersKey[];
extern const char kSecureKey[];
diff --git a/chrome/common/extensions/api/declarative_web_request.json b/chrome/common/extensions/api/declarative_web_request.json
index b297523..23bf186 100644
--- a/chrome/common/extensions/api/declarative_web_request.json
+++ b/chrome/common/extensions/api/declarative_web_request.json
@@ -10,7 +10,7 @@
{
"id": "HeaderFilter",
"type": "object",
- "description": "Filters request headers for various criteria.",
+ "description": "Filters request headers for various criteria. Multiple criteria are evaluated as a conjunction.",
"properties": {
"namePrefix": {
"description" : "Matches if the header name starts with the specified string.",
@@ -88,6 +88,18 @@
"description": "Matches if the MIME media type of a response (from the HTTP Content-Type header) is <em>not</em> contained in the list.",
"items": { "type": "string" }
},
+ "requestHeaders": {
+ "type": "array",
+ "optional": true,
+ "description": "Matches if some of the request headers is matched by one of the HeaderFilters.",
+ "items": { "$ref": "HeaderFilter" }
+ },
+ "excludeRequestHeaders": {
+ "type": "array",
+ "optional": true,
+ "description": "Matches if none of the request headers is matched by any of the HeaderFilters.",
+ "items": { "$ref": "HeaderFilter" }
+ },
"responseHeaders": {
"type": "array",
"optional": true,
@@ -97,7 +109,7 @@
"excludeResponseHeaders": {
"type": "array",
"optional": true,
- "description": "Matches if none of the response headers is matched by one of the HeaderFilters.",
+ "description": "Matches if none of the response headers is matched by any of the HeaderFilters.",
"items": { "$ref": "HeaderFilter" }
},
"thirdPartyForCookies": {
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_declarative.js b/chrome/test/data/extensions/api_test/webrequest/test_declarative.js
index 9edb294..6d54189 100644
--- a/chrome/test/data/extensions/api_test/webrequest/test_declarative.js
+++ b/chrome/test/data/extensions/api_test/webrequest/test_declarative.js
@@ -185,7 +185,7 @@ runTests([
'resourceType': ["main_frame"],
'contentType': ["text/plain"],
'excludeContentType': ["image/png"],
- 'responseHeaders': [{ nameContains: ["content", "type"] } ],
+ 'responseHeaders': [{ nameContains: ["content", "type"] }],
'excludeResponseHeaders': [{ valueContains: "nonsense" }] })],
'actions': [new CancelRequest()]}
],
@@ -619,4 +619,35 @@ runTests([
}
);
},
+
+ function testRequestHeaders() {
+ ignoreUnexpected = true;
+ expect(
+ [
+ { label: "onErrorOccurred",
+ event: "onErrorOccurred",
+ details: {
+ url: getURLHttpSimple(),
+ fromCache: false,
+ error: "net::ERR_BLOCKED_BY_CLIENT"
+ }
+ },
+ ],
+ [ ["onErrorOccurred"] ]);
+ onRequest.addRules(
+ [ {'conditions': [
+ new RequestMatcher({
+ 'url': {
+ 'pathSuffix': ".html",
+ 'ports': [testServerPort, [1000, 2000]],
+ 'schemes': ["http"]
+ },
+ 'requestHeaders': [{ nameContains: "" }],
+ 'excludeRequestHeaders': [{ valueContains: ["", "value123"] }]
+ })],
+ 'actions': [new CancelRequest()]}
+ ],
+ function() {navigateAndWait(getURLHttpSimple());}
+ );
+ },
]);