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 @@
#include "base/basictypes.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_rule.h"
#include "chrome/common/extensions/matcher/url_matcher.h"
namespace extensions {
......
......@@ -12,13 +12,16 @@
#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/web_request/web_request_api_helpers.h"
#include "chrome/common/extensions/extension_error_utils.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"
namespace {
// Error messages.
const char kUnknownConditionAttribute[] = "Unknown matching condition: '%s'";
const char kInvalidValue[] = "Condition '%s' has an invalid value";
const char kUnknownConditionAttribute[] = "Unknown matching condition: '*'";
const char kInvalidValue[] = "Condition '*' has an invalid value";
}
namespace helpers = extension_web_request_api_helpers;
......@@ -38,8 +41,9 @@ WebRequestConditionAttribute::~WebRequestConditionAttribute() {}
// static
bool WebRequestConditionAttribute::IsKnownType(
const std::string& instance_type) {
return WebRequestConditionAttributeResourceType::IsMatchingType(
instance_type);
return
WebRequestConditionAttributeResourceType::IsMatchingType(instance_type) ||
WebRequestConditionAttributeContentType::IsMatchingType(instance_type);
}
// static
......@@ -50,13 +54,15 @@ WebRequestConditionAttribute::Create(
std::string* error) {
if (WebRequestConditionAttributeResourceType::IsMatchingType(name)) {
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);
}
//
// WebRequestConditionAttributeResourceType
//
......@@ -83,9 +89,10 @@ WebRequestConditionAttributeResourceType::Create(
std::string* error) {
DCHECK(IsMatchingType(name));
const ListValue* value_as_list = 0;
const ListValue* value_as_list = NULL;
if (!value->GetAsList(&value_as_list)) {
*error = base::StringPrintf(kInvalidValue, keys::kResourceTypeKey);
*error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue,
keys::kResourceTypeKey);
return scoped_ptr<WebRequestConditionAttribute>(NULL);
}
......@@ -97,7 +104,8 @@ WebRequestConditionAttributeResourceType::Create(
ResourceType::Type type = ResourceType::LAST_TYPE;
if (!value_as_list->GetString(i, &resource_type_string) ||
!helpers::ParseResourceType(resource_type_string, &type)) {
*error = base::StringPrintf(kInvalidValue, keys::kResourceTypeKey);
*error = ExtensionErrorUtils::FormatErrorMessage(kInvalidValue,
keys::kResourceTypeKey);
return scoped_ptr<WebRequestConditionAttribute>(NULL);
}
passed_types.push_back(type);
......@@ -130,4 +138,77 @@ WebRequestConditionAttributeResourceType::GetType() const {
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
......@@ -31,7 +31,8 @@ namespace extensions {
class WebRequestConditionAttribute {
public:
enum Type {
CONDITION_RESOURCE_TYPE
CONDITION_RESOURCE_TYPE,
CONDITION_CONTENT_TYPE
};
WebRequestConditionAttribute();
......@@ -100,6 +101,36 @@ class 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
#endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_WEBREQUEST_WEBREQUEST_CONDITION_ATTRIBUTE_H_
......@@ -4,12 +4,14 @@
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h"
#include "content/public/browser/resource_request_info.h"
#include "net/url_request/url_request_test_util.h"
#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
......@@ -44,6 +46,12 @@ TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) {
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());
// Test success
error.clear();
result = WebRequestConditionAttribute::Create(
......@@ -83,4 +91,53 @@ TEST(WebRequestConditionAttributeTest, TestResourceType) {
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
......@@ -12,6 +12,7 @@ const char kOnRequest[] = "declarativeWebRequest.onRequest";
// Keys of dictionaries.
const char kCookieKey[] = "cookie";
const char kContentTypeKey[] = "contentType";
const char kDirectionKey[] = "direction";
const char kDomainKey[] = "domain";
const char kExpiresKey[] = "expires";
......
......@@ -15,6 +15,7 @@ extern const char kOnRequest[];
// Keys of dictionaries.
extern const char kCookieKey[];
extern const char kContentTypeKey[];
extern const char kDirectionKey[];
extern const char kDomainKey[];
extern const char kExpiresKey[];
......
......@@ -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.",
"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": {
"type": "string", "enum": ["declarativeWebRequest.RequestMatcher"],
"nodoc": true
......
......@@ -773,6 +773,36 @@ very fast URL matching algorithm for hundreds of thousands of URLs.
<!-- OBJECT METHODS -->
<!-- OBJECT EVENT FIELDS -->
<!-- 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>
</dl>
......
......@@ -51,6 +51,11 @@ function getURLHttpRedirectTest() {
"files/extensions/api_test/webrequest/declarative/a.html");
}
function getURLHttpWithHeaders() {
return getServerURL(
"files/extensions/api_test/webrequest/declarative/headers.html");
}
function getURLSetCookie() {
return getServerURL('set-cookie?Foo=Bar');
}
......@@ -83,7 +88,7 @@ runTests([
{ label: "onErrorOccurred",
event: "onErrorOccurred",
details: {
url: getURLHttpSimple(),
url: getURLHttpWithHeaders(),
fromCache: false,
error: "net::ERR_BLOCKED_BY_CLIENT"
}
......@@ -98,10 +103,11 @@ runTests([
'ports': [testServerPort, [1000, 2000]],
'schemes': ["http"]
},
'resourceType': ["main_frame"]})],
'resourceType': ["main_frame"],
'contentType': ["text/html"]})],
'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