Commit 840eccef authored by yoz@chromium.org's avatar yoz@chromium.org

Add condition attribute for MIME media types from Content-Type header.

This only supports positive tests.

BUG=112155

Review URL: https://chromiumcodereview.appspot.com/10843065

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150126 0039d316-1c4b-4281-b951-d872f2087c98
parent 8fd9eeee
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/memory/linked_ptr.h" #include "base/memory/linked_ptr.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h"
#include "chrome/common/extensions/matcher/url_matcher.h" #include "chrome/common/extensions/matcher/url_matcher.h"
namespace extensions { namespace extensions {
......
...@@ -12,13 +12,16 @@ ...@@ -12,13 +12,16 @@
#include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
#include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "content/public/browser/resource_request_info.h" #include "content/public/browser/resource_request_info.h"
#include "net/http/http_util.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h" #include "net/url_request/url_request.h"
namespace { namespace {
// Error messages. // Error messages.
const char kUnknownConditionAttribute[] = "Unknown matching condition: '%s'"; const char kUnknownConditionAttribute[] = "Unknown matching condition: '*'";
const char kInvalidValue[] = "Condition '%s' has an invalid value"; const char kInvalidValue[] = "Condition '*' has an invalid value";
} }
namespace helpers = extension_web_request_api_helpers; namespace helpers = extension_web_request_api_helpers;
...@@ -38,8 +41,9 @@ WebRequestConditionAttribute::~WebRequestConditionAttribute() {} ...@@ -38,8 +41,9 @@ WebRequestConditionAttribute::~WebRequestConditionAttribute() {}
// static // static
bool WebRequestConditionAttribute::IsKnownType( bool WebRequestConditionAttribute::IsKnownType(
const std::string& instance_type) { const std::string& instance_type) {
return WebRequestConditionAttributeResourceType::IsMatchingType( return
instance_type); WebRequestConditionAttributeResourceType::IsMatchingType(instance_type) ||
WebRequestConditionAttributeContentType::IsMatchingType(instance_type);
} }
// static // static
...@@ -50,13 +54,15 @@ WebRequestConditionAttribute::Create( ...@@ -50,13 +54,15 @@ WebRequestConditionAttribute::Create(
std::string* error) { std::string* error) {
if (WebRequestConditionAttributeResourceType::IsMatchingType(name)) { if (WebRequestConditionAttributeResourceType::IsMatchingType(name)) {
return WebRequestConditionAttributeResourceType::Create(name, value, error); return WebRequestConditionAttributeResourceType::Create(name, value, error);
} else if (WebRequestConditionAttributeContentType::IsMatchingType(name)) {
return WebRequestConditionAttributeContentType::Create(name, value, error);
} }
*error = base::StringPrintf(kUnknownConditionAttribute, name.c_str()); *error = ExtensionErrorUtils::FormatErrorMessage(kUnknownConditionAttribute,
name);
return scoped_ptr<WebRequestConditionAttribute>(NULL); return scoped_ptr<WebRequestConditionAttribute>(NULL);
} }
// //
// WebRequestConditionAttributeResourceType // WebRequestConditionAttributeResourceType
// //
...@@ -83,9 +89,10 @@ WebRequestConditionAttributeResourceType::Create( ...@@ -83,9 +89,10 @@ WebRequestConditionAttributeResourceType::Create(
std::string* error) { std::string* error) {
DCHECK(IsMatchingType(name)); DCHECK(IsMatchingType(name));
const ListValue* value_as_list = 0; const ListValue* value_as_list = NULL;
if (!value->GetAsList(&value_as_list)) { if (!value->GetAsList(&value_as_list)) {
*error = base::StringPrintf(kInvalidValue, keys::kResourceTypeKey); *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue,
keys::kResourceTypeKey);
return scoped_ptr<WebRequestConditionAttribute>(NULL); return scoped_ptr<WebRequestConditionAttribute>(NULL);
} }
...@@ -97,7 +104,8 @@ WebRequestConditionAttributeResourceType::Create( ...@@ -97,7 +104,8 @@ WebRequestConditionAttributeResourceType::Create(
ResourceType::Type type = ResourceType::LAST_TYPE; ResourceType::Type type = ResourceType::LAST_TYPE;
if (!value_as_list->GetString(i, &resource_type_string) || if (!value_as_list->GetString(i, &resource_type_string) ||
!helpers::ParseResourceType(resource_type_string, &type)) { !helpers::ParseResourceType(resource_type_string, &type)) {
*error = base::StringPrintf(kInvalidValue, keys::kResourceTypeKey); *error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue,
keys::kResourceTypeKey);
return scoped_ptr<WebRequestConditionAttribute>(NULL); return scoped_ptr<WebRequestConditionAttribute>(NULL);
} }
passed_types.push_back(type); passed_types.push_back(type);
...@@ -130,4 +138,77 @@ WebRequestConditionAttributeResourceType::GetType() const { ...@@ -130,4 +138,77 @@ WebRequestConditionAttributeResourceType::GetType() const {
return CONDITION_RESOURCE_TYPE; return CONDITION_RESOURCE_TYPE;
} }
//
// WebRequestConditionAttributeContentType
//
WebRequestConditionAttributeContentType::
WebRequestConditionAttributeContentType(
const std::vector<std::string>& content_types)
: content_types_(content_types) {}
WebRequestConditionAttributeContentType::
~WebRequestConditionAttributeContentType() {}
// static
bool WebRequestConditionAttributeContentType::IsMatchingType(
const std::string& instance_type) {
return instance_type == keys::kContentTypeKey;
}
// static
scoped_ptr<WebRequestConditionAttribute>
WebRequestConditionAttributeContentType::Create(
const std::string& name,
const base::Value* value,
std::string* error) {
std::vector<std::string> content_types;
const ListValue* value_as_list = NULL;
if (!value->GetAsList(&value_as_list)) {
*error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue,
keys::kContentTypeKey);
return scoped_ptr<WebRequestConditionAttribute>(NULL);
}
for (ListValue::const_iterator it = value_as_list->begin();
it != value_as_list->end(); ++it) {
std::string content_type;
if (!(*it)->GetAsString(&content_type)) {
*error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue,
keys::kContentTypeKey);
return scoped_ptr<WebRequestConditionAttribute>(NULL);
}
content_types.push_back(content_type);
}
return scoped_ptr<WebRequestConditionAttribute>(
new WebRequestConditionAttributeContentType(content_types));
}
int WebRequestConditionAttributeContentType::GetStages() const {
return ON_HEADERS_RECEIVED;
}
bool WebRequestConditionAttributeContentType::IsFulfilled(
const WebRequestRule::RequestData& request_data) {
if (!(request_data.stage & GetStages()))
return false;
std::string content_type;
request_data.original_response_headers->GetNormalizedHeader(
net::HttpRequestHeaders::kContentType, &content_type);
std::string mime_type;
std::string charset;
bool had_charset;
net::HttpUtil::ParseContentType(
content_type, &mime_type, &charset, &had_charset, NULL);
return std::find(content_types_.begin(), content_types_.end(),
mime_type) != content_types_.end();
}
WebRequestConditionAttribute::Type
WebRequestConditionAttributeContentType::GetType() const {
return CONDITION_CONTENT_TYPE;
}
} // namespace extensions } // namespace extensions
...@@ -31,7 +31,8 @@ namespace extensions { ...@@ -31,7 +31,8 @@ namespace extensions {
class WebRequestConditionAttribute { class WebRequestConditionAttribute {
public: public:
enum Type { enum Type {
CONDITION_RESOURCE_TYPE CONDITION_RESOURCE_TYPE,
CONDITION_CONTENT_TYPE
}; };
WebRequestConditionAttribute(); WebRequestConditionAttribute();
...@@ -100,6 +101,36 @@ class WebRequestConditionAttributeResourceType ...@@ -100,6 +101,36 @@ class WebRequestConditionAttributeResourceType
DISALLOW_COPY_AND_ASSIGN(WebRequestConditionAttributeResourceType); DISALLOW_COPY_AND_ASSIGN(WebRequestConditionAttributeResourceType);
}; };
// Condition that checks whether a response's Content-Type header has a
// certain MIME media type.
class WebRequestConditionAttributeContentType
: public WebRequestConditionAttribute {
public:
virtual ~WebRequestConditionAttributeContentType();
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)
OVERRIDE;
virtual Type GetType() const OVERRIDE;
private:
explicit WebRequestConditionAttributeContentType(
const std::vector<std::string>& content_types);
std::vector<std::string> content_types_;
DISALLOW_COPY_AND_ASSIGN(WebRequestConditionAttributeContentType);
};
} // namespace extensions } // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_WEBREQUEST_WEBREQUEST_CONDITION_ATTRIBUTE_H_ #endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_WEBREQUEST_WEBREQUEST_CONDITION_ATTRIBUTE_H_
...@@ -4,12 +4,14 @@ ...@@ -4,12 +4,14 @@
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
#include "base/file_path.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h"
#include "content/public/browser/resource_request_info.h" #include "content/public/browser/resource_request_info.h"
#include "net/url_request/url_request_test_util.h" #include "net/url_request/url_request_test_util.h"
#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace { namespace {
...@@ -44,6 +46,12 @@ TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) { ...@@ -44,6 +46,12 @@ TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) {
EXPECT_FALSE(error.empty()); EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get()); EXPECT_FALSE(result.get());
error.clear();
result = WebRequestConditionAttribute::Create(
keys::kContentTypeKey, &string_value, &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
// Test success // Test success
error.clear(); error.clear();
result = WebRequestConditionAttribute::Create( result = WebRequestConditionAttribute::Create(
...@@ -83,4 +91,53 @@ TEST(WebRequestConditionAttributeTest, TestResourceType) { ...@@ -83,4 +91,53 @@ TEST(WebRequestConditionAttributeTest, TestResourceType) {
WebRequestRule::RequestData(&url_request_fail, ON_BEFORE_REQUEST))); WebRequestRule::RequestData(&url_request_fail, ON_BEFORE_REQUEST)));
} }
TEST(WebRequestConditionAttributeTest, TestContentType) {
// Necessary for TestURLRequest.
MessageLoop message_loop(MessageLoop::TYPE_IO);
std::string error;
scoped_ptr<WebRequestConditionAttribute> result;
net::TestServer test_server(
net::TestServer::TYPE_HTTP,
net::TestServer::kLocalhost,
FilePath(FILE_PATH_LITERAL(
"chrome/test/data/extensions/api_test/webrequest/declarative")));
ASSERT_TRUE(test_server.Start());
TestURLRequestContext context;
TestDelegate delegate;
TestURLRequest url_request(test_server.GetURL("headers.html"),
&delegate, &context);
url_request.Start();
MessageLoop::current()->Run();
ListValue content_types;
content_types.Append(Value::CreateStringValue("text/html"));
scoped_ptr<WebRequestConditionAttribute> attribute_ok =
WebRequestConditionAttribute::Create(
keys::kContentTypeKey, &content_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_ok.get());
EXPECT_FALSE(attribute_ok->IsFulfilled(
WebRequestRule::RequestData(&url_request, ON_BEFORE_REQUEST,
url_request.response_headers())));
EXPECT_TRUE(attribute_ok->IsFulfilled(
WebRequestRule::RequestData(&url_request, ON_HEADERS_RECEIVED,
url_request.response_headers())));
content_types.Clear();
content_types.Append(Value::CreateStringValue("something/invalid"));
scoped_ptr<WebRequestConditionAttribute> attribute_fail =
WebRequestConditionAttribute::Create(
keys::kContentTypeKey, &content_types, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(attribute_fail.get());
EXPECT_FALSE(attribute_fail->IsFulfilled(
WebRequestRule::RequestData(&url_request, ON_HEADERS_RECEIVED,
url_request.response_headers())));
}
} // namespace extensions } // namespace extensions
...@@ -12,6 +12,7 @@ const char kOnRequest[] = "declarativeWebRequest.onRequest"; ...@@ -12,6 +12,7 @@ const char kOnRequest[] = "declarativeWebRequest.onRequest";
// Keys of dictionaries. // Keys of dictionaries.
const char kCookieKey[] = "cookie"; const char kCookieKey[] = "cookie";
const char kContentTypeKey[] = "contentType";
const char kDirectionKey[] = "direction"; const char kDirectionKey[] = "direction";
const char kDomainKey[] = "domain"; const char kDomainKey[] = "domain";
const char kExpiresKey[] = "expires"; const char kExpiresKey[] = "expires";
......
...@@ -15,6 +15,7 @@ extern const char kOnRequest[]; ...@@ -15,6 +15,7 @@ extern const char kOnRequest[];
// Keys of dictionaries. // Keys of dictionaries.
extern const char kCookieKey[]; extern const char kCookieKey[];
extern const char kContentTypeKey[];
extern const char kDirectionKey[]; extern const char kDirectionKey[];
extern const char kDomainKey[]; extern const char kDomainKey[];
extern const char kExpiresKey[]; extern const char kExpiresKey[];
......
...@@ -23,6 +23,12 @@ ...@@ -23,6 +23,12 @@
"description": "Matches if the request type of a request is contained in the list. Requests that cannot match any of the types will be filtered out.", "description": "Matches if the request type of a request is contained in the list. Requests that cannot match any of the types will be filtered out.",
"items": { "type": "string", "enum": ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"] } "items": { "type": "string", "enum": ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"] }
}, },
"contentType": {
"type": "array",
"optional": true,
"description": "Matches if the MIME media type of a response (from the HTTP Content-Type header) is contained in the list.",
"items": { "type": "string" }
},
"instanceType": { "instanceType": {
"type": "string", "enum": ["declarativeWebRequest.RequestMatcher"], "type": "string", "enum": ["declarativeWebRequest.RequestMatcher"],
"nodoc": true "nodoc": true
......
...@@ -773,6 +773,36 @@ very fast URL matching algorithm for hundreds of thousands of URLs. ...@@ -773,6 +773,36 @@ very fast URL matching algorithm for hundreds of thousands of URLs.
<!-- OBJECT METHODS --> <!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS --> <!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS --> <!-- FUNCTION PARAMETERS -->
</div>
</div><div>
<div>
<dt>
<var>contentType</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
<span class="optional">optional</span>
<span id="typeTemplate">
<span>
<span>
array of <span><span>
<span>
<span>string</span>
</span>
</span></span>
</span>
</span>
</span>
)
</div>
</em>
</dt>
<dd>Matches if the MIME media type of a response (from the HTTP Content-Type header) is contained in the list.</dd>
<!-- OBJECT PROPERTIES -->
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- FUNCTION PARAMETERS -->
</div> </div>
</div> </div>
</dl> </dl>
......
...@@ -51,6 +51,11 @@ function getURLHttpRedirectTest() { ...@@ -51,6 +51,11 @@ function getURLHttpRedirectTest() {
"files/extensions/api_test/webrequest/declarative/a.html"); "files/extensions/api_test/webrequest/declarative/a.html");
} }
function getURLHttpWithHeaders() {
return getServerURL(
"files/extensions/api_test/webrequest/declarative/headers.html");
}
function getURLSetCookie() { function getURLSetCookie() {
return getServerURL('set-cookie?Foo=Bar'); return getServerURL('set-cookie?Foo=Bar');
} }
...@@ -83,7 +88,7 @@ runTests([ ...@@ -83,7 +88,7 @@ runTests([
{ label: "onErrorOccurred", { label: "onErrorOccurred",
event: "onErrorOccurred", event: "onErrorOccurred",
details: { details: {
url: getURLHttpSimple(), url: getURLHttpWithHeaders(),
fromCache: false, fromCache: false,
error: "net::ERR_BLOCKED_BY_CLIENT" error: "net::ERR_BLOCKED_BY_CLIENT"
} }
...@@ -98,10 +103,11 @@ runTests([ ...@@ -98,10 +103,11 @@ runTests([
'ports': [testServerPort, [1000, 2000]], 'ports': [testServerPort, [1000, 2000]],
'schemes': ["http"] 'schemes': ["http"]
}, },
'resourceType': ["main_frame"]})], 'resourceType': ["main_frame"],
'contentType': ["text/html"]})],
'actions': [new CancelRequest()]} 'actions': [new CancelRequest()]}
], ],
function() {navigateAndWait(getURLHttpSimple());} function() {navigateAndWait(getURLHttpWithHeaders());}
); );
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment