Commit 95b0d8a2 authored by battre@chromium.org's avatar battre@chromium.org

Support Cookie modifications in Declarative WebRequest API


BUG=112155
TEST=no
TBR=ben@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149838 0039d316-1c4b-4281-b951-d872f2087c98
parent 4b74884a
...@@ -41,6 +41,42 @@ const char kEmptyDocumentUrl[] = "data:text/html,"; ...@@ -41,6 +41,42 @@ const char kEmptyDocumentUrl[] = "data:text/html,";
} \ } \
} while (0) } while (0)
scoped_ptr<helpers::RequestCookie> ParseRequestCookie(
const DictionaryValue* dict) {
scoped_ptr<helpers::RequestCookie> result(new helpers::RequestCookie);
std::string tmp;
if (dict->GetString(keys::kNameKey, &tmp))
result->name.reset(new std::string(tmp));
if (dict->GetString(keys::kValueKey, &tmp))
result->value.reset(new std::string(tmp));
return result.Pass();
}
scoped_ptr<helpers::ResponseCookie> ParseResponseCookie(
const DictionaryValue* dict) {
scoped_ptr<helpers::ResponseCookie> result(new helpers::ResponseCookie);
std::string string_tmp;
int int_tmp = 0;
bool bool_tmp = false;
if (dict->GetString(keys::kNameKey, &string_tmp))
result->name.reset(new std::string(string_tmp));
if (dict->GetString(keys::kValueKey, &string_tmp))
result->value.reset(new std::string(string_tmp));
if (dict->GetString(keys::kExpiresKey, &string_tmp))
result->expires.reset(new std::string(string_tmp));
if (dict->GetInteger(keys::kMaxAgeKey, &int_tmp))
result->max_age.reset(new int(int_tmp));
if (dict->GetString(keys::kDomainKey, &string_tmp))
result->domain.reset(new std::string(string_tmp));
if (dict->GetString(keys::kPathKey, &string_tmp))
result->path.reset(new std::string(string_tmp));
if (dict->GetBoolean(keys::kSecureKey, &bool_tmp))
result->secure.reset(new bool(bool_tmp));
if (dict->GetBoolean(keys::kHttpOnlyKey, &bool_tmp))
result->http_only.reset(new bool(bool_tmp));
return result.Pass();
}
// Helper function for WebRequestActions that can be instantiated by just // Helper function for WebRequestActions that can be instantiated by just
// calling the constructor. // calling the constructor.
template <class T> template <class T>
...@@ -145,6 +181,96 @@ scoped_ptr<WebRequestAction> CreateIgnoreRulesAction( ...@@ -145,6 +181,96 @@ scoped_ptr<WebRequestAction> CreateIgnoreRulesAction(
new WebRequestIgnoreRulesAction(minium_priority)); new WebRequestIgnoreRulesAction(minium_priority));
} }
scoped_ptr<WebRequestAction> CreateRequestCookieAction(
const base::DictionaryValue* dict,
std::string* error,
bool* bad_message) {
using extension_web_request_api_helpers::RequestCookieModification;
linked_ptr<RequestCookieModification> modification(
new RequestCookieModification);
// Get modification type.
std::string instance_type;
INPUT_FORMAT_VALIDATE(
dict->GetString(keys::kInstanceTypeKey, &instance_type));
if (instance_type == keys::kAddRequestCookieType)
modification->type = helpers::ADD;
else if (instance_type == keys::kEditRequestCookieType)
modification->type = helpers::EDIT;
else if (instance_type == keys::kRemoveRequestCookieType)
modification->type = helpers::REMOVE;
else
INPUT_FORMAT_VALIDATE(false);
// Get filter.
if (modification->type == helpers::EDIT ||
modification->type == helpers::REMOVE) {
const DictionaryValue* filter = NULL;
INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
modification->filter = ParseRequestCookie(filter);
}
// Get new value.
if (modification->type == helpers::ADD) {
const DictionaryValue* value = NULL;
INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
modification->modification = ParseRequestCookie(value);
} else if (modification->type == helpers::EDIT) {
const DictionaryValue* value = NULL;
INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
modification->modification = ParseRequestCookie(value);
}
return scoped_ptr<WebRequestAction>(
new WebRequestRequestCookieAction(modification));
}
scoped_ptr<WebRequestAction> CreateResponseCookieAction(
const base::DictionaryValue* dict,
std::string* error,
bool* bad_message) {
using extension_web_request_api_helpers::ResponseCookieModification;
linked_ptr<ResponseCookieModification> modification(
new ResponseCookieModification);
// Get modification type.
std::string instance_type;
INPUT_FORMAT_VALIDATE(
dict->GetString(keys::kInstanceTypeKey, &instance_type));
if (instance_type == keys::kAddResponseCookieType)
modification->type = helpers::ADD;
else if (instance_type == keys::kEditResponseCookieType)
modification->type = helpers::EDIT;
else if (instance_type == keys::kRemoveResponseCookieType)
modification->type = helpers::REMOVE;
else
INPUT_FORMAT_VALIDATE(false);
// Get filter.
if (modification->type == helpers::EDIT ||
modification->type == helpers::REMOVE) {
const DictionaryValue* filter = NULL;
INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kFilterKey, &filter));
modification->filter = ParseResponseCookie(filter);
}
// Get new value.
if (modification->type == helpers::ADD) {
const DictionaryValue* value = NULL;
INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kCookieKey, &value));
modification->modification = ParseResponseCookie(value);
} else if (modification->type == helpers::EDIT) {
const DictionaryValue* value = NULL;
INPUT_FORMAT_VALIDATE(dict->GetDictionary(keys::kModificationKey, &value));
modification->modification = ParseResponseCookie(value);
}
return scoped_ptr<WebRequestAction>(
new WebRequestResponseCookieAction(modification));
}
struct WebRequestActionFactory { struct WebRequestActionFactory {
// Factory methods for WebRequestAction instances. |dict| contains the json // Factory methods for WebRequestAction instances. |dict| contains the json
// dictionary that describes the action. |error| is used to return error // dictionary that describes the action. |error| is used to return error
...@@ -158,10 +284,18 @@ struct WebRequestActionFactory { ...@@ -158,10 +284,18 @@ struct WebRequestActionFactory {
std::map<std::string, FactoryMethod> factory_methods; std::map<std::string, FactoryMethod> factory_methods;
WebRequestActionFactory() { WebRequestActionFactory() {
factory_methods[keys::kAddRequestCookieType] =
&CreateRequestCookieAction;
factory_methods[keys::kAddResponseCookieType] =
&CreateResponseCookieAction;
factory_methods[keys::kAddResponseHeaderType] = factory_methods[keys::kAddResponseHeaderType] =
&CreateAddResponseHeaderAction; &CreateAddResponseHeaderAction;
factory_methods[keys::kCancelRequestType] = factory_methods[keys::kCancelRequestType] =
&CallConstructorFactoryMethod<WebRequestCancelAction>; &CallConstructorFactoryMethod<WebRequestCancelAction>;
factory_methods[keys::kEditRequestCookieType] =
&CreateRequestCookieAction;
factory_methods[keys::kEditResponseCookieType] =
&CreateResponseCookieAction;
factory_methods[keys::kRedirectByRegExType] = factory_methods[keys::kRedirectByRegExType] =
&CreateRedirectRequestByRegExAction; &CreateRedirectRequestByRegExAction;
factory_methods[keys::kRedirectRequestType] = factory_methods[keys::kRedirectRequestType] =
...@@ -171,6 +305,10 @@ struct WebRequestActionFactory { ...@@ -171,6 +305,10 @@ struct WebRequestActionFactory {
WebRequestRedirectToTransparentImageAction>; WebRequestRedirectToTransparentImageAction>;
factory_methods[keys::kRedirectToEmptyDocumentType] = factory_methods[keys::kRedirectToEmptyDocumentType] =
&CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>; &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>;
factory_methods[keys::kRemoveRequestCookieType] =
&CreateRequestCookieAction;
factory_methods[keys::kRemoveResponseCookieType] =
&CreateResponseCookieAction;
factory_methods[keys::kSetRequestHeaderType] = factory_methods[keys::kSetRequestHeaderType] =
&CreateSetRequestHeaderAction; &CreateSetRequestHeaderAction;
factory_methods[keys::kRemoveRequestHeaderType] = factory_methods[keys::kRemoveRequestHeaderType] =
...@@ -762,4 +900,74 @@ LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta( ...@@ -762,4 +900,74 @@ LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::CreateDelta(
return LinkedPtrEventResponseDelta(NULL); return LinkedPtrEventResponseDelta(NULL);
} }
//
// WebRequestRequestCookieAction
//
WebRequestRequestCookieAction::WebRequestRequestCookieAction(
linked_ptr<RequestCookieModification> request_cookie_modification)
: request_cookie_modification_(request_cookie_modification) {
CHECK(request_cookie_modification_.get());
}
WebRequestRequestCookieAction::~WebRequestRequestCookieAction() {}
int WebRequestRequestCookieAction::GetStages() const {
return ON_BEFORE_SEND_HEADERS;
}
WebRequestAction::Type WebRequestRequestCookieAction::GetType() const {
return WebRequestAction::ACTION_MODIFY_REQUEST_COOKIE;
}
LinkedPtrEventResponseDelta WebRequestRequestCookieAction::CreateDelta(
net::URLRequest* request,
RequestStages request_stage,
const WebRequestRule::OptionalRequestData& optional_request_data,
const std::string& extension_id,
const base::Time& extension_install_time) const {
CHECK(request_stage & GetStages());
LinkedPtrEventResponseDelta result(
new extension_web_request_api_helpers::EventResponseDelta(
extension_id, extension_install_time));
result->request_cookie_modifications.push_back(
request_cookie_modification_);
return result;
}
//
// WebRequestResponseCookieAction
//
WebRequestResponseCookieAction::WebRequestResponseCookieAction(
linked_ptr<ResponseCookieModification> response_cookie_modification)
: response_cookie_modification_(response_cookie_modification) {
CHECK(response_cookie_modification_.get());
}
WebRequestResponseCookieAction::~WebRequestResponseCookieAction() {}
int WebRequestResponseCookieAction::GetStages() const {
return ON_HEADERS_RECEIVED;
}
WebRequestAction::Type WebRequestResponseCookieAction::GetType() const {
return WebRequestAction::ACTION_MODIFY_RESPONSE_COOKIE;
}
LinkedPtrEventResponseDelta WebRequestResponseCookieAction::CreateDelta(
net::URLRequest* request,
RequestStages request_stage,
const WebRequestRule::OptionalRequestData& optional_request_data,
const std::string& extension_id,
const base::Time& extension_install_time) const {
CHECK(request_stage & GetStages());
LinkedPtrEventResponseDelta result(
new extension_web_request_api_helpers::EventResponseDelta(
extension_id, extension_install_time));
result->response_cookie_modifications.push_back(
response_cookie_modification_);
return result;
}
} // namespace extensions } // namespace extensions
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/memory/linked_ptr.h" #include "base/memory/linked_ptr.h"
#include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h"
#include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
#include "chrome/common/extensions/api/events.h" #include "chrome/common/extensions/api/events.h"
#include "googleurl/src/gurl.h" #include "googleurl/src/gurl.h"
#include "unicode/regex.h" #include "unicode/regex.h"
...@@ -43,7 +44,6 @@ typedef linked_ptr<extension_web_request_api_helpers::EventResponseDelta> ...@@ -43,7 +44,6 @@ typedef linked_ptr<extension_web_request_api_helpers::EventResponseDelta>
LinkedPtrEventResponseDelta; LinkedPtrEventResponseDelta;
// Base class for all WebRequestActions of the declarative Web Request API. // Base class for all WebRequestActions of the declarative Web Request API.
//
class WebRequestAction { class WebRequestAction {
public: public:
// Type identifiers for concrete WebRequestActions. // Type identifiers for concrete WebRequestActions.
...@@ -58,6 +58,8 @@ class WebRequestAction { ...@@ -58,6 +58,8 @@ class WebRequestAction {
ACTION_ADD_RESPONSE_HEADER, ACTION_ADD_RESPONSE_HEADER,
ACTION_REMOVE_RESPONSE_HEADER, ACTION_REMOVE_RESPONSE_HEADER,
ACTION_IGNORE_RULES, ACTION_IGNORE_RULES,
ACTION_MODIFY_REQUEST_COOKIE,
ACTION_MODIFY_RESPONSE_COOKIE,
}; };
WebRequestAction(); WebRequestAction();
...@@ -389,8 +391,55 @@ class WebRequestIgnoreRulesAction : public WebRequestAction { ...@@ -389,8 +391,55 @@ class WebRequestIgnoreRulesAction : public WebRequestAction {
DISALLOW_COPY_AND_ASSIGN(WebRequestIgnoreRulesAction); DISALLOW_COPY_AND_ASSIGN(WebRequestIgnoreRulesAction);
}; };
// TODO(battre) Implement further actions: // Action that instructs to modify (add, edit, remove) a request cookie.
// Redirect by RegEx, Cookie manipulations, ... class WebRequestRequestCookieAction : public WebRequestAction {
public:
typedef extension_web_request_api_helpers::RequestCookieModification
RequestCookieModification;
explicit WebRequestRequestCookieAction(
linked_ptr<RequestCookieModification> request_cookie_modification);
virtual ~WebRequestRequestCookieAction();
// Implementation of WebRequestAction:
virtual int GetStages() const OVERRIDE;
virtual Type GetType() const OVERRIDE;
virtual LinkedPtrEventResponseDelta CreateDelta(
net::URLRequest* request,
RequestStages request_stage,
const WebRequestRule::OptionalRequestData& optional_request_data,
const std::string& extension_id,
const base::Time& extension_install_time) const OVERRIDE;
private:
linked_ptr<RequestCookieModification> request_cookie_modification_;
DISALLOW_COPY_AND_ASSIGN(WebRequestRequestCookieAction);
};
// Action that instructs to modify (add, edit, remove) a response cookie.
class WebRequestResponseCookieAction : public WebRequestAction {
public:
typedef extension_web_request_api_helpers::ResponseCookieModification
ResponseCookieModification;
explicit WebRequestResponseCookieAction(
linked_ptr<ResponseCookieModification> response_cookie_modification);
virtual ~WebRequestResponseCookieAction();
// Implementation of WebRequestAction:
virtual int GetStages() const OVERRIDE;
virtual Type GetType() const OVERRIDE;
virtual LinkedPtrEventResponseDelta CreateDelta(
net::URLRequest* request,
RequestStages request_stage,
const WebRequestRule::OptionalRequestData& optional_request_data,
const std::string& extension_id,
const base::Time& extension_install_time) const OVERRIDE;
private:
linked_ptr<ResponseCookieModification> response_cookie_modification_;
DISALLOW_COPY_AND_ASSIGN(WebRequestResponseCookieAction);
};
} // namespace extensions } // namespace extensions
......
...@@ -11,20 +11,34 @@ namespace declarative_webrequest_constants { ...@@ -11,20 +11,34 @@ namespace declarative_webrequest_constants {
const char kOnRequest[] = "declarativeWebRequest.onRequest"; const char kOnRequest[] = "declarativeWebRequest.onRequest";
// Keys of dictionaries. // Keys of dictionaries.
const char kCookieKey[] = "cookie";
const char kDirectionKey[] = "direction";
const char kDomainKey[] = "domain";
const char kExpiresKey[] = "expires";
const char kFilterKey[] ="filter";
const char kFromKey[] = "from"; const char kFromKey[] = "from";
const char kHttpOnlyKey[] = "httpOnly";
const char kInstanceTypeKey[] = "instanceType"; const char kInstanceTypeKey[] = "instanceType";
const char kLowerPriorityThanKey[] = "lowerPriorityThan"; const char kLowerPriorityThanKey[] = "lowerPriorityThan";
const char kMaxAgeKey[] = "maxAge";
const char kModificationKey[] = "modification";
const char kNameKey[] = "name"; const char kNameKey[] = "name";
const char kPathKey[] = "path";
const char kRedirectUrlKey[] = "redirectUrl"; const char kRedirectUrlKey[] = "redirectUrl";
const char kResourceTypeKey[] = "resourceType"; const char kResourceTypeKey[] = "resourceType";
const char kSecureKey[] = "secure";
const char kToKey[] = "to"; const char kToKey[] = "to";
const char kUrlKey[] = "url"; const char kUrlKey[] = "url";
const char kValueKey[] = "value"; const char kValueKey[] = "value";
// Values of dictionaries, in particular instance types // Values of dictionaries, in particular instance types
const char kAddResponseHeaderType[] = const char kAddRequestCookieType[] = "declarativeWebRequest.AddRequestCookie";
"declarativeWebRequest.AddResponseHeader"; const char kAddResponseCookieType[] = "declarativeWebRequest.AddResponseCookie";
const char kAddResponseHeaderType[] = "declarativeWebRequest.AddResponseHeader";
const char kCancelRequestType[] = "declarativeWebRequest.CancelRequest"; const char kCancelRequestType[] = "declarativeWebRequest.CancelRequest";
const char kEditRequestCookieType[] = "declarativeWebRequest.EditRequestCookie";
const char kEditResponseCookieType[] =
"declarativeWebRequest.EditResponseCookie";
const char kIgnoreRulesType[] = "declarativeWebRequest.IgnoreRules"; const char kIgnoreRulesType[] = "declarativeWebRequest.IgnoreRules";
const char kRedirectRequestType[] = "declarativeWebRequest.RedirectRequest"; const char kRedirectRequestType[] = "declarativeWebRequest.RedirectRequest";
const char kRedirectByRegExType[] = const char kRedirectByRegExType[] =
...@@ -33,11 +47,16 @@ const char kRedirectToEmptyDocumentType[] = ...@@ -33,11 +47,16 @@ const char kRedirectToEmptyDocumentType[] =
"declarativeWebRequest.RedirectToEmptyDocument"; "declarativeWebRequest.RedirectToEmptyDocument";
const char kRedirectToTransparentImageType[] = const char kRedirectToTransparentImageType[] =
"declarativeWebRequest.RedirectToTransparentImage"; "declarativeWebRequest.RedirectToTransparentImage";
const char kRemoveRequestCookieType[] =
"declarativeWebRequest.RemoveRequestCookie";
const char kRemoveRequestHeaderType[] = const char kRemoveRequestHeaderType[] =
"declarativeWebRequest.RemoveRequestHeader"; "declarativeWebRequest.RemoveRequestHeader";
const char kRemoveResponseCookieType[] =
"declarativeWebRequest.RemoveResponseCookie";
const char kRemoveResponseHeaderType[] = const char kRemoveResponseHeaderType[] =
"declarativeWebRequest.RemoveResponseHeader"; "declarativeWebRequest.RemoveResponseHeader";
const char kRequestMatcherType[] = "declarativeWebRequest.RequestMatcher"; const char kRequestMatcherType[] = "declarativeWebRequest.RequestMatcher";
const char kSetRequestHeaderType[] = "declarativeWebRequest.SetRequestHeader"; const char kSetRequestHeaderType[] = "declarativeWebRequest.SetRequestHeader";
} // namespace declarative_webrequest_constants } // namespace declarative_webrequest_constants
} // namespace extensions } // namespace extensions
...@@ -14,25 +14,41 @@ namespace declarative_webrequest_constants { ...@@ -14,25 +14,41 @@ namespace declarative_webrequest_constants {
extern const char kOnRequest[]; extern const char kOnRequest[];
// Keys of dictionaries. // Keys of dictionaries.
extern const char kCookieKey[];
extern const char kDirectionKey[];
extern const char kDomainKey[];
extern const char kExpiresKey[];
extern const char kFilterKey[];
extern const char kFromKey[]; extern const char kFromKey[];
extern const char kHttpOnlyKey[];
extern const char kInstanceTypeKey[]; extern const char kInstanceTypeKey[];
extern const char kLowerPriorityThanKey[]; extern const char kLowerPriorityThanKey[];
extern const char kMaxAgeKey[];
extern const char kModificationKey[];
extern const char kNameKey[]; extern const char kNameKey[];
extern const char kPathKey[];
extern const char kRedirectUrlKey[]; extern const char kRedirectUrlKey[];
extern const char kResourceTypeKey[]; extern const char kResourceTypeKey[];
extern const char kSecureKey[];
extern const char kToKey[]; extern const char kToKey[];
extern const char kUrlKey[]; extern const char kUrlKey[];
extern const char kValueKey[]; extern const char kValueKey[];
// Values of dictionaries, in particular instance types // Values of dictionaries, in particular instance types
extern const char kAddRequestCookieType[];
extern const char kAddResponseCookieType[];
extern const char kAddResponseHeaderType[]; extern const char kAddResponseHeaderType[];
extern const char kCancelRequestType[]; extern const char kCancelRequestType[];
extern const char kEditRequestCookieType[];
extern const char kEditResponseCookieType[];
extern const char kIgnoreRulesType[]; extern const char kIgnoreRulesType[];
extern const char kRedirectByRegExType[]; extern const char kRedirectByRegExType[];
extern const char kRedirectRequestType[]; extern const char kRedirectRequestType[];
extern const char kRedirectToEmptyDocumentType[]; extern const char kRedirectToEmptyDocumentType[];
extern const char kRedirectToTransparentImageType[]; extern const char kRedirectToTransparentImageType[];
extern const char kRemoveRequestCookieType[];
extern const char kRemoveRequestHeaderType[]; extern const char kRemoveRequestHeaderType[];
extern const char kRemoveResponseCookieType[];
extern const char kRemoveResponseHeaderType[]; extern const char kRemoveResponseHeaderType[];
extern const char kRequestMatcherType[]; extern const char kRequestMatcherType[];
extern const char kSetRequestHeaderType[]; extern const char kSetRequestHeaderType[];
......
...@@ -40,6 +40,69 @@ namespace extension_web_request_api_helpers { ...@@ -40,6 +40,69 @@ namespace extension_web_request_api_helpers {
typedef std::pair<std::string, std::string> ResponseHeader; typedef std::pair<std::string, std::string> ResponseHeader;
typedef std::vector<ResponseHeader> ResponseHeaders; typedef std::vector<ResponseHeader> ResponseHeaders;
// Data container for RequestCookies as defined in the declarative WebRequest
// API definition.
struct RequestCookie {
RequestCookie();
~RequestCookie();
scoped_ptr<std::string> name;
scoped_ptr<std::string> value;
private:
DISALLOW_COPY_AND_ASSIGN(RequestCookie);
};
// Data container for ResponseCookies as defined in the declarative WebRequest
// API definition.
struct ResponseCookie {
ResponseCookie();
~ResponseCookie();
scoped_ptr<std::string> name;
scoped_ptr<std::string> value;
scoped_ptr<std::string> expires;
scoped_ptr<int> max_age;
scoped_ptr<std::string> domain;
scoped_ptr<std::string> path;
scoped_ptr<bool> secure;
scoped_ptr<bool> http_only;
private:
DISALLOW_COPY_AND_ASSIGN(ResponseCookie);
};
enum CookieModificationType {
ADD,
EDIT,
REMOVE,
};
struct RequestCookieModification {
RequestCookieModification();
~RequestCookieModification();
CookieModificationType type;
// Used for EDIT and REMOVE. NULL for ADD.
scoped_ptr<RequestCookie> filter;
// Used for ADD and EDIT. NULL for REMOVE.
scoped_ptr<RequestCookie> modification;
private:
DISALLOW_COPY_AND_ASSIGN(RequestCookieModification);
};
struct ResponseCookieModification {
ResponseCookieModification();
~ResponseCookieModification();
CookieModificationType type;
// Used for EDIT and REMOVE.
scoped_ptr<ResponseCookie> filter;
// Used for ADD and EDIT.
scoped_ptr<ResponseCookie> modification;
private:
DISALLOW_COPY_AND_ASSIGN(ResponseCookieModification);
};
typedef std::vector<linked_ptr<RequestCookieModification> >
RequestCookieModifications;
typedef std::vector<linked_ptr<ResponseCookieModification> >
ResponseCookieModifications;
// Contains the modification an extension wants to perform on an event. // Contains the modification an extension wants to perform on an event.
struct EventResponseDelta { struct EventResponseDelta {
// ID of the extension that sent this response. // ID of the extension that sent this response.
...@@ -70,6 +133,12 @@ struct EventResponseDelta { ...@@ -70,6 +133,12 @@ struct EventResponseDelta {
// Authentication Credentials to use. // Authentication Credentials to use.
scoped_ptr<net::AuthCredentials> auth_credentials; scoped_ptr<net::AuthCredentials> auth_credentials;
// Modifications to cookies in request headers.
RequestCookieModifications request_cookie_modifications;
// Modifications to cookies in response headers.
ResponseCookieModifications response_cookie_modifications;
EventResponseDelta(const std::string& extension_id, EventResponseDelta(const std::string& extension_id,
const base::Time& extension_install_time); const base::Time& extension_install_time);
~EventResponseDelta(); ~EventResponseDelta();
...@@ -144,6 +213,14 @@ void MergeOnBeforeRequestResponses( ...@@ -144,6 +213,14 @@ void MergeOnBeforeRequestResponses(
GURL* new_url, GURL* new_url,
std::set<std::string>* conflicting_extensions, std::set<std::string>* conflicting_extensions,
const net::BoundNetLog* net_log); const net::BoundNetLog* net_log);
// Modifies the "Cookie" header in |request_headers| according to
// |deltas.request_cookie_modifications|. Conflicts are currently ignored
// silently.
void MergeCookiesInOnBeforeSendHeadersResponses(
const EventResponseDeltas& deltas,
net::HttpRequestHeaders* request_headers,
std::set<std::string>* conflicting_extensions,
const net::BoundNetLog* net_log);
// Modifies the headers in |request_headers| according to |deltas|. Conflicts // Modifies the headers in |request_headers| according to |deltas|. Conflicts
// are tried to be resolved. // are tried to be resolved.
void MergeOnBeforeSendHeadersResponses( void MergeOnBeforeSendHeadersResponses(
...@@ -151,6 +228,16 @@ void MergeOnBeforeSendHeadersResponses( ...@@ -151,6 +228,16 @@ void MergeOnBeforeSendHeadersResponses(
net::HttpRequestHeaders* request_headers, net::HttpRequestHeaders* request_headers,
std::set<std::string>* conflicting_extensions, std::set<std::string>* conflicting_extensions,
const net::BoundNetLog* net_log); const net::BoundNetLog* net_log);
// Modifies the "Set-Cookie" headers in |override_response_headers| according to
// |deltas.response_cookie_modifications|. If |override_response_headers| is
// NULL, a copy of |original_response_headers| is created. Conflicts are
// currently ignored silently.
void MergeCookiesInOnHeadersReceivedResponses(
const EventResponseDeltas& deltas,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
std::set<std::string>* conflicting_extensions,
const net::BoundNetLog* net_log);
// Stores a copy of |original_response_header| into |override_response_headers| // Stores a copy of |original_response_header| into |override_response_headers|
// that is modified according to |deltas|. If |deltas| does not instruct to // that is modified according to |deltas|. If |deltas| does not instruct to
// modify the response headers, |override_response_headers| remains empty. // modify the response headers, |override_response_headers| remains empty.
......
...@@ -48,6 +48,8 @@ using helpers::EventResponseDeltas; ...@@ -48,6 +48,8 @@ using helpers::EventResponseDeltas;
using helpers::InDecreasingExtensionInstallationTimeOrder; using helpers::InDecreasingExtensionInstallationTimeOrder;
using helpers::MergeCancelOfResponses; using helpers::MergeCancelOfResponses;
using helpers::MergeOnBeforeRequestResponses; using helpers::MergeOnBeforeRequestResponses;
using helpers::RequestCookieModification;
using helpers::ResponseCookieModification;
using helpers::ResponseHeader; using helpers::ResponseHeader;
using helpers::ResponseHeaders; using helpers::ResponseHeaders;
using helpers::StringToCharList; using helpers::StringToCharList;
...@@ -1281,6 +1283,162 @@ TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeSendHeadersResponses) { ...@@ -1281,6 +1283,162 @@ TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeSendHeadersResponses) {
EXPECT_EQ(3u, capturing_net_log.GetSize()); EXPECT_EQ(3u, capturing_net_log.GetSize());
} }
TEST(ExtensionWebRequestHelpersTest,
TestMergeOnBeforeSendHeadersResponses_Cookies) {
net::HttpRequestHeaders base_headers;
base_headers.AddHeaderFromString(
"Cookie: name=value; name2=value2; name3=value3");
net::CapturingBoundNetLog capturing_net_log;
net::BoundNetLog net_log = capturing_net_log.bound();
std::set<std::string> conflicting_extensions;
std::string header_value;
EventResponseDeltas deltas;
linked_ptr<RequestCookieModification> add_cookie =
make_linked_ptr(new RequestCookieModification);
add_cookie->type = helpers::ADD;
add_cookie->modification.reset(new helpers::RequestCookie);
add_cookie->modification->name.reset(new std::string("name4"));
add_cookie->modification->value.reset(new std::string("\"value 4\""));
linked_ptr<RequestCookieModification> add_cookie_2 =
make_linked_ptr(new RequestCookieModification);
add_cookie_2->type = helpers::ADD;
add_cookie_2->modification.reset(new helpers::RequestCookie);
add_cookie_2->modification->name.reset(new std::string("name"));
add_cookie_2->modification->value.reset(new std::string("new value"));
linked_ptr<RequestCookieModification> edit_cookie =
make_linked_ptr(new RequestCookieModification);
edit_cookie->type = helpers::EDIT;
edit_cookie->filter.reset(new helpers::RequestCookie);
edit_cookie->filter->name.reset(new std::string("name2"));
edit_cookie->modification.reset(new helpers::RequestCookie);
edit_cookie->modification->value.reset(new std::string("new value"));
linked_ptr<RequestCookieModification> remove_cookie =
make_linked_ptr(new RequestCookieModification);
remove_cookie->type = helpers::REMOVE;
remove_cookie->filter.reset(new helpers::RequestCookie);
remove_cookie->filter->name.reset(new std::string("name3"));
linked_ptr<RequestCookieModification> operations[] = {
add_cookie, add_cookie_2, edit_cookie, remove_cookie
};
for (size_t i = 0; i < arraysize(operations); ++i) {
linked_ptr<EventResponseDelta> delta(
new EventResponseDelta("extid0", base::Time::FromInternalValue(i * 5)));
delta->request_cookie_modifications.push_back(operations[i]);
deltas.push_back(delta);
}
deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
net::HttpRequestHeaders headers1;
headers1.MergeFrom(base_headers);
MergeOnBeforeSendHeadersResponses(
deltas, &headers1, &conflicting_extensions, &net_log);
EXPECT_TRUE(headers1.HasHeader("Cookie"));
ASSERT_TRUE(headers1.GetHeader("Cookie", &header_value));
EXPECT_EQ("name=new value; name2=new value; name4=\"value 4\"", header_value);
EXPECT_EQ(0u, conflicting_extensions.size());
EXPECT_EQ(0u, capturing_net_log.GetSize());
}
TEST(ExtensionWebRequestHelpersTest,
TestMergeCookiesInOnHeadersReceivedResponses) {
net::CapturingBoundNetLog capturing_net_log;
net::BoundNetLog net_log = capturing_net_log.bound();
std::set<std::string> conflicting_extensions;
std::string header_value;
EventResponseDeltas deltas;
char base_headers_string[] =
"HTTP/1.0 200 OK\r\n"
"Foo: Bar\r\n"
"Set-Cookie: name=value; DOMAIN=google.com; Secure\r\n"
"Set-Cookie: name2=value2\r\n"
"Set-Cookie: name3=value3\r\n"
"\r\n";
scoped_refptr<net::HttpResponseHeaders> base_headers(
new net::HttpResponseHeaders(
net::HttpUtil::AssembleRawHeaders(
base_headers_string, sizeof(base_headers_string))));
// Check that we can handle if not touching the response headers.
linked_ptr<EventResponseDelta> d0(
new EventResponseDelta("extid0", base::Time::FromInternalValue(3000)));
deltas.push_back(d0);
scoped_refptr<net::HttpResponseHeaders> new_headers0;
MergeCookiesInOnHeadersReceivedResponses(
deltas, base_headers.get(), &new_headers0, &conflicting_extensions,
&net_log);
EXPECT_FALSE(new_headers0.get());
EXPECT_EQ(0u, conflicting_extensions.size());
EXPECT_EQ(0u, capturing_net_log.GetSize());
linked_ptr<ResponseCookieModification> add_cookie =
make_linked_ptr(new ResponseCookieModification);
add_cookie->type = helpers::ADD;
add_cookie->modification.reset(new helpers::ResponseCookie);
add_cookie->modification->name.reset(new std::string("name4"));
add_cookie->modification->value.reset(new std::string("\"value4\""));
linked_ptr<ResponseCookieModification> edit_cookie =
make_linked_ptr(new ResponseCookieModification);
edit_cookie->type = helpers::EDIT;
edit_cookie->filter.reset(new helpers::ResponseCookie);
edit_cookie->filter->name.reset(new std::string("name2"));
edit_cookie->modification.reset(new helpers::ResponseCookie);
edit_cookie->modification->value.reset(new std::string("new value"));
linked_ptr<ResponseCookieModification> edit_cookie_2 =
make_linked_ptr(new ResponseCookieModification);
edit_cookie_2->type = helpers::EDIT;
edit_cookie_2->filter.reset(new helpers::ResponseCookie);
edit_cookie_2->filter->secure.reset(new bool(false));
edit_cookie_2->modification.reset(new helpers::ResponseCookie);
edit_cookie_2->modification->secure.reset(new bool(true));
linked_ptr<ResponseCookieModification> remove_cookie =
make_linked_ptr(new ResponseCookieModification);
remove_cookie->type = helpers::REMOVE;
remove_cookie->filter.reset(new helpers::ResponseCookie);
remove_cookie->filter->name.reset(new std::string("name3"));
linked_ptr<ResponseCookieModification> operations[] = {
add_cookie, edit_cookie, edit_cookie_2, remove_cookie
};
for (size_t i = 0; i < arraysize(operations); ++i) {
linked_ptr<EventResponseDelta> delta(
new EventResponseDelta("extid0", base::Time::FromInternalValue(i * 5)));
delta->response_cookie_modifications.push_back(operations[i]);
deltas.push_back(delta);
}
deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
scoped_refptr<net::HttpResponseHeaders> headers1(
new net::HttpResponseHeaders(
net::HttpUtil::AssembleRawHeaders(
base_headers_string, sizeof(base_headers_string))));
scoped_refptr<net::HttpResponseHeaders> new_headers1;
MergeCookiesInOnHeadersReceivedResponses(
deltas, headers1.get(), &new_headers1, &conflicting_extensions, &net_log);
EXPECT_TRUE(new_headers1->HasHeader("Foo"));
void* iter = NULL;
std::string cookie_string;
std::set<std::string> expected_cookies;
expected_cookies.insert("name=value; domain=google.com; secure");
expected_cookies.insert("name2=value2; secure");
expected_cookies.insert("name4=\"value4\"; secure");
std::set<std::string> actual_cookies;
while (new_headers1->EnumerateHeader(&iter, "Set-Cookie", &cookie_string))
actual_cookies.insert(cookie_string);
EXPECT_EQ(expected_cookies, actual_cookies);
EXPECT_EQ(0u, conflicting_extensions.size());
EXPECT_EQ(0u, capturing_net_log.GetSize());
}
TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) { TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) {
net::CapturingBoundNetLog capturing_net_log; net::CapturingBoundNetLog capturing_net_log;
net::BoundNetLog net_log = capturing_net_log.bound(); net::BoundNetLog net_log = capturing_net_log.bound();
......
...@@ -180,6 +180,168 @@ ...@@ -180,6 +180,168 @@
"description": "If set, rules with a lower priority than the specified value are ignored. This boundary is not persited, it affects only rules and their actions of the same network request stage. TODO(battre): Explain network request stages." "description": "If set, rules with a lower priority than the specified value are ignored. This boundary is not persited, it affects only rules and their actions of the same network request stage. TODO(battre): Explain network request stages."
} }
} }
},
{
"id": "declarativeWebRequest.RequestCookie",
"description": "A filter or specification of a cookie in HTTP Requests.",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of a cookie.",
"optional": true
},
"value": {
"type": "string",
"description": "Value of a cookie, may be padded in double-quotes.",
"optional": true
}
}
},
{
"id": "declarativeWebRequest.ResponseCookie",
"description": "A filter or specification of a cookie in HTTP Responses.",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of a cookie.",
"optional": true
},
"value": {
"type": "string",
"description": "Value of a cookie, may be padded in double-quotes.",
"optional": true
},
"expires": {
"type": "string",
"description": "Value of the Expires cookie attribute.",
"optional": true
},
"maxAge": {
"type": "number",
"description": "Value of the Max-Age cookie attribute",
"optional": true
},
"domain": {
"type": "string",
"description": "Value of the Domain cookie attribute.",
"optional": true
},
"path": {
"type": "string",
"description": "Value of the Path cookie attribute.",
"optional": true
},
"secure": {
"type": "string",
"description": "Existence of the Secure cookie attribute.",
"optional": true
},
"httpOnly": {
"type": "string",
"description": "Existence of the HttpOnly cookie attribute.",
"optional": true
}
}
},
{
"id": "declarativeWebRequest.AddRequestCookie",
"description": "Adds a cookie to the request or overrides a cookie, in case another cookie of the same name exists already. Note that it is preferred to use the Cookies API because this is computationally less expensive.",
"type": "object",
"properties": {
"instanceType": {
"type": "string", "enum": ["declarativeWebRequest.AddRequestCookie"],
"nodoc": true
},
"cookie": {
"$ref": "declarativeWebRequest.RequestCookie",
"description": "Cookie to be added to the request. No field may be undefined."
}
}
},
{
"id": "declarativeWebRequest.AddResponseCookie",
"description": "Adds a cookie to the response or overrides a cookie, in case another cookie of the same name exists already. Note that it is preferred to use the Cookies API because this is computationally less expensive.",
"type": "object",
"properties": {
"instanceType": {
"type": "string", "enum": ["declarativeWebRequest.AddResponseCookie"],
"nodoc": true
},
"cookie": {
"$ref": "declarativeWebRequest.ResponseCookie",
"description": "Cookie to be added to the response. The name and value need to be specified."
}
}
},
{
"id": "declarativeWebRequest.EditRequestCookie",
"description": "Edits one or more cookies of request. Note that it is preferred to use the Cookies API because this is computationally less expensive.",
"type": "object",
"properties": {
"instanceType": {
"type": "string", "enum": ["declarativeWebRequest.EditRequestCookie"],
"nodoc": true
},
"filter": {
"$ref": "declarativeWebRequest.RequestCookie",
"description": "Filter for cookies that will be modified. All empty entries are ignored."
},
"modification": {
"$ref": "declarativeWebRequest.RequestCookie",
"description": "Attributes that shall be overridden in cookies that machted the filter. Attributes that are set to an empty string are removed."
}
}
},
{
"id": "declarativeWebRequest.EditResponseCookie",
"description": "Edits one or more cookies of response. Note that it is preferred to use the Cookies API because this is computationally less expensive.",
"type": "object",
"properties": {
"instanceType": {
"type": "string", "enum": ["declarativeWebRequest.EditResponseCookie"],
"nodoc": true
},
"filter": {
"$ref": "declarativeWebRequest.ResponseCookie",
"description": "Filter for cookies that will be modified. All empty entries are ignored."
},
"modification": {
"$ref": "declarativeWebRequest.ResponseCookie",
"description": "Attributes that shall be overridden in cookies that machted the filter. Attributes that are set to an empty string are removed."
}
}
},
{
"id": "declarativeWebRequest.RemoveRequestCookie",
"description": "Removes one or more cookies of request. Note that it is preferred to use the Cookies API because this is computationally less expensive.",
"type": "object",
"properties": {
"instanceType": {
"type": "string", "enum": ["declarativeWebRequest.RemoveRequestCookie"],
"nodoc": true
},
"filter": {
"$ref": "declarativeWebRequest.RequestCookie",
"description": "Filter for cookies that will be removed. All empty entries are ignored."
}
}
},
{
"id": "declarativeWebRequest.RemoveResponseCookie",
"description": "Removes one or more cookies of response. Note that it is preferred to use the Cookies API because this is computationally less expensive.",
"type": "object",
"properties": {
"instanceType": {
"type": "string", "enum": ["declarativeWebRequest.RemoveResponseCookie"],
"nodoc": true
},
"filter": {
"$ref": "declarativeWebRequest.ResponseCookie",
"description": "Filter for cookies that will be removed. All empty entries are ignored."
}
}
} }
], ],
"functions": [ "functions": [
...@@ -192,15 +354,21 @@ ...@@ -192,15 +354,21 @@
"supportsRules": true, "supportsRules": true,
"conditions": ["declarativeWebRequest.RequestMatcher"], "conditions": ["declarativeWebRequest.RequestMatcher"],
"actions": [ "actions": [
"declarativeWebRequest.AddRequestCookie",
"declarativeWebRequest.AddResponseCookie",
"declarativeWebRequest.AddResponseHeader", "declarativeWebRequest.AddResponseHeader",
"declarativeWebRequest.CancelRequest", "declarativeWebRequest.CancelRequest",
"declarativeWebRequest.EditRequestCookie",
"declarativeWebRequest.EditResponseCookie",
"declarativeWebRequest.RedirectRequest", "declarativeWebRequest.RedirectRequest",
"declarativeWebRequest.RedirectToTransparentImage", "declarativeWebRequest.RedirectToTransparentImage",
"declarativeWebRequest.RedirectToEmptyDocument", "declarativeWebRequest.RedirectToEmptyDocument",
"declarativeWebRequest.RedirectByRegEx", "declarativeWebRequest.RedirectByRegEx",
"declarativeWebRequest.SetRequestHeader", "declarativeWebRequest.RemoveRequestCookie",
"declarativeWebRequest.RemoveResponseCookie",
"declarativeWebRequest.RemoveRequestHeader", "declarativeWebRequest.RemoveRequestHeader",
"declarativeWebRequest.RemoveResponseHeader", "declarativeWebRequest.RemoveResponseHeader",
"declarativeWebRequest.SetRequestHeader",
"declarativeWebRequest.IgnoreRules" "declarativeWebRequest.IgnoreRules"
] ]
} }
......
...@@ -68,4 +68,22 @@ chromeHidden.registerCustomHook('declarativeWebRequest', function(api) { ...@@ -68,4 +68,22 @@ chromeHidden.registerCustomHook('declarativeWebRequest', function(api) {
chrome.declarativeWebRequest.IgnoreRules = function(parameters) { chrome.declarativeWebRequest.IgnoreRules = function(parameters) {
setupInstance(this, parameters, 'IgnoreRules'); setupInstance(this, parameters, 'IgnoreRules');
}; };
chrome.declarativeWebRequest.AddRequestCookie = function(parameters) {
setupInstance(this, parameters, 'AddRequestCookie');
};
chrome.declarativeWebRequest.AddResponseCookie = function(parameters) {
setupInstance(this, parameters, 'AddResponseCookie');
};
chrome.declarativeWebRequest.EditRequestCookie = function(parameters) {
setupInstance(this, parameters, 'EditRequestCookie');
};
chrome.declarativeWebRequest.EditResponseCookie = function(parameters) {
setupInstance(this, parameters, 'EditResponseCookie');
};
chrome.declarativeWebRequest.RemoveRequestCookie = function(parameters) {
setupInstance(this, parameters, 'RemoveRequestCookie');
};
chrome.declarativeWebRequest.RemoveResponseCookie = function(parameters) {
setupInstance(this, parameters, 'RemoveResponseCookie');
};
}); });
...@@ -21,6 +21,12 @@ var RemoveResponseHeader = ...@@ -21,6 +21,12 @@ var RemoveResponseHeader =
chrome.declarativeWebRequest.RemoveResponseHeader; chrome.declarativeWebRequest.RemoveResponseHeader;
var IgnoreRules = var IgnoreRules =
chrome.declarativeWebRequest.IgnoreRules; chrome.declarativeWebRequest.IgnoreRules;
var AddRequestCookie = chrome.declarativeWebRequest.AddRequestCookie;
var AddResponseCookie = chrome.declarativeWebRequest.AddResponseCookie;
var EditRequestCookie = chrome.declarativeWebRequest.EditRequestCookie;
var EditResponseCookie = chrome.declarativeWebRequest.EditResponseCookie;
var RemoveRequestCookie = chrome.declarativeWebRequest.RemoveRequestCookie;
var RemoveResponseCookie = chrome.declarativeWebRequest.RemoveResponseCookie;
// Constants as functions, not to be called until after runTests. // Constants as functions, not to be called until after runTests.
function getURLEchoUserAgent() { function getURLEchoUserAgent() {
...@@ -49,10 +55,20 @@ function getURLSetCookie() { ...@@ -49,10 +55,20 @@ function getURLSetCookie() {
return getServerURL('set-cookie?Foo=Bar'); return getServerURL('set-cookie?Foo=Bar');
} }
function getURLSetCookie2() {
return getServerURL('set-cookie?passedCookie=Foo&editedCookie=Foo&' +
'deletedCookie=Foo');
}
function getURLEchoCookie() {
return getServerURL('echoheader?Cookie');
}
function getURLHttpXHRData() { function getURLHttpXHRData() {
return getServerURL("files/extensions/api_test/webrequest/xhr/data.json", return getServerURL("files/extensions/api_test/webrequest/xhr/data.json",
"b.com"); "b.com");
} }
function getURLHttpSimpleOnB() { function getURLHttpSimpleOnB() {
return getServerURL("files/extensions/api_test/webrequest/simpleLoad/a.html", return getServerURL("files/extensions/api_test/webrequest/simpleLoad/a.html",
"b.com"); "b.com");
...@@ -342,6 +358,82 @@ runTests([ ...@@ -342,6 +358,82 @@ runTests([
); );
}, },
function testEditRequestCookies() {
ignoreUnexpected = true;
expect();
var cookie1 = {name: "requestCookie1", value: "foo"};
var cookie2 = {name: "requestCookie2", value: "foo"};
onRequest.addRules(
[ {conditions: [new RequestMatcher({})],
actions: [
// We exploit the fact that cookies are first added, then modified
// and finally removed.
new AddRequestCookie({cookie: cookie1}),
new AddRequestCookie({cookie: cookie2}),
new EditRequestCookie({filter: {name: "requestCookie1"},
modification: {value: "bar"}}),
new RemoveRequestCookie({filter: {name: "requestCookie2"}})
]}
],
function() {
navigateAndWait(getURLEchoCookie(), function() {
chrome.test.listenOnce(chrome.extension.onRequest, function(request) {
chrome.test.assertTrue(request.pass, "Invalid cookies. " +
JSON.stringify(request.cookies));
});
chrome.tabs.executeScript(tabId, {code:
"function hasCookie(name, value) {" +
" var entry = name + '=' + value;" +
" return document.body.innerText.indexOf(entry) >= 0;" +
"};" +
"var result = {};" +
"result.pass = hasCookie('requestCookie1', 'bar') && " +
" !hasCookie('requestCookie1', 'foo') && " +
" !hasCookie('requestCookie2', 'foo');" +
"result.cookies = document.body.innerText;" +
"chrome.extension.sendRequest(result);"});
});
}
);
},
function testEditResponseCookies() {
ignoreUnexpected = true;
expect();
onRequest.addRules(
[ {conditions: [new RequestMatcher({})],
actions: [
new AddResponseCookie({cookie: {name: "addedCookie", value: "Foo"}}),
new EditResponseCookie({filter: {name: "editedCookie"},
modification: {value: "bar"}}),
new RemoveResponseCookie({filter: {name: "deletedCookie"}})
]}
],
function() {
navigateAndWait(getURLSetCookie2(), function() {
chrome.test.listenOnce(chrome.extension.onRequest, function(request) {
chrome.test.assertTrue(request.pass, "Invalid cookies. " +
JSON.stringify(request.cookies));
});
chrome.tabs.executeScript(tabId, {code:
"var cookies = document.cookie.split('; ');" +
"var cookieMap = {};" +
"for (var i = 0; i < cookies.length; ++i) {" +
" var cookieParts = cookies[i].split('=');" +
" cookieMap[cookieParts[0]] = cookieParts[1];" +
"}" +
"var result = {};" +
"result.cookies = cookieMap;" +
"result.pass = (cookieMap.passedCookie === 'Foo') &&" +
" (cookieMap.addedCookie === 'Foo') &&" +
" (cookieMap.editedCookie === 'bar') &&" +
" !cookieMap.hasOwnProperty('deletedCookie');" +
"chrome.extension.sendRequest(result);"});
});
}
);
},
function testPermission() { function testPermission() {
// Test that a redirect is ignored if the extension has no permission. // Test that a redirect is ignored if the extension has no permission.
// we load a.html from a.com and issue an XHR to b.com, which is not // we load a.html from a.com and issue an XHR to b.com, which is not
...@@ -375,5 +467,4 @@ runTests([ ...@@ -375,5 +467,4 @@ runTests([
} }
); );
}, },
]); ]);
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