diff options
author | battre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-30 09:11:41 +0000 |
---|---|---|
committer | battre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-30 09:11:41 +0000 |
commit | 8dc590b5e3165d31c730ae2f5cf8a2df0878f699 (patch) | |
tree | 75b62dfb7216b6fc28ef650aa9016c71e2b76ce7 | |
parent | 1f7eba7875a15cc7318f3ce2c039e1ab5f31cd1d (diff) | |
download | chromium_src-8dc590b5e3165d31c730ae2f5cf8a2df0878f699.zip chromium_src-8dc590b5e3165d31c730ae2f5cf8a2df0878f699.tar.gz chromium_src-8dc590b5e3165d31c730ae2f5cf8a2df0878f699.tar.bz2 |
Add support for response header manipulation in Declarative WebRequest API
BUG=112155
TEST=no
Review URL: https://chromiumcodereview.appspot.com/10451071
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139509 0039d316-1c4b-4281-b951-d872f2087c98
15 files changed, 561 insertions, 43 deletions
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc index a6b5e0b..271afc1 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc @@ -9,6 +9,7 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/stringprintf.h" +#include "base/string_util.h" #include "base/values.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h" @@ -79,6 +80,30 @@ scoped_ptr<WebRequestAction> CreateRemoveRequestHeaderAction( new WebRequestRemoveRequestHeaderAction(name)); } +scoped_ptr<WebRequestAction> CreateAddResponseHeaderAction( + const base::DictionaryValue* dict, + std::string* error, + bool* bad_message) { + std::string name; + std::string value; + INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); + INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value)); + return scoped_ptr<WebRequestAction>( + new WebRequestAddResponseHeaderAction(name, value)); +} + +scoped_ptr<WebRequestAction> CreateRemoveResponseHeaderAction( + const base::DictionaryValue* dict, + std::string* error, + bool* bad_message) { + std::string name; + std::string value; + INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); + bool has_value = dict->GetString(keys::kValueKey, &value); + return scoped_ptr<WebRequestAction>( + new WebRequestRemoveResponseHeaderAction(name, value, has_value)); +} + scoped_ptr<WebRequestAction> CreateIgnoreRulesAction( const base::DictionaryValue* dict, std::string* error, @@ -103,6 +128,8 @@ struct WebRequestActionFactory { std::map<std::string, FactoryMethod> factory_methods; WebRequestActionFactory() { + factory_methods[keys::kAddResponseHeaderType] = + &CreateAddResponseHeaderAction; factory_methods[keys::kCancelRequestType] = &CallConstructorFactoryMethod<WebRequestCancelAction>; factory_methods[keys::kRedirectRequestType] = @@ -116,6 +143,8 @@ struct WebRequestActionFactory { &CreateSetRequestHeaderAction; factory_methods[keys::kRemoveRequestHeaderType] = &CreateRemoveRequestHeaderAction; + factory_methods[keys::kRemoveResponseHeaderType] = + &CreateRemoveResponseHeaderAction; factory_methods[keys::kIgnoreRulesType] = &CreateIgnoreRulesAction; } @@ -198,13 +227,15 @@ scoped_ptr<WebRequestActionSet> WebRequestActionSet::Create( std::list<LinkedPtrEventResponseDelta> WebRequestActionSet::CreateDeltas( net::URLRequest* request, RequestStages request_stage, + const WebRequestRule::OptionalRequestData& optional_request_data, const std::string& extension_id, const base::Time& extension_install_time) const { std::list<LinkedPtrEventResponseDelta> result; for (Actions::const_iterator i = actions_.begin(); i != actions_.end(); ++i) { if ((*i)->GetStages() & request_stage) { LinkedPtrEventResponseDelta delta = (*i)->CreateDelta(request, - request_stage, extension_id, extension_install_time); + request_stage, optional_request_data, extension_id, + extension_install_time); if (delta.get()) result.push_back(delta); } @@ -240,6 +271,7 @@ WebRequestAction::Type WebRequestCancelAction::GetType() const { LinkedPtrEventResponseDelta WebRequestCancelAction::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()); @@ -270,6 +302,7 @@ WebRequestAction::Type WebRequestRedirectAction::GetType() const { LinkedPtrEventResponseDelta WebRequestRedirectAction::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()); @@ -305,6 +338,7 @@ LinkedPtrEventResponseDelta WebRequestRedirectToTransparentImageAction::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()); @@ -338,6 +372,7 @@ LinkedPtrEventResponseDelta WebRequestRedirectToEmptyDocumentAction::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()); @@ -374,6 +409,7 @@ LinkedPtrEventResponseDelta WebRequestSetRequestHeaderAction::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()); @@ -408,6 +444,7 @@ LinkedPtrEventResponseDelta WebRequestRemoveRequestHeaderAction::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()); @@ -419,6 +456,107 @@ WebRequestRemoveRequestHeaderAction::CreateDelta( } // +// WebRequestAddResponseHeaderAction +// + +WebRequestAddResponseHeaderAction::WebRequestAddResponseHeaderAction( + const std::string& name, + const std::string& value) + : name_(name), + value_(value) { +} + +WebRequestAddResponseHeaderAction::~WebRequestAddResponseHeaderAction() {} + +int WebRequestAddResponseHeaderAction::GetStages() const { + return ON_HEADERS_RECEIVED; +} + +WebRequestAction::Type +WebRequestAddResponseHeaderAction::GetType() const { + return WebRequestAction::ACTION_ADD_RESPONSE_HEADER; +} + +LinkedPtrEventResponseDelta +WebRequestAddResponseHeaderAction::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)); + + net::HttpResponseHeaders* headers = + optional_request_data.original_response_headers; + if (!headers) + return result; + + // Don't generate the header if it exists already. + if (headers->HasHeaderValue(name_, value_)) + return result; + + result->added_response_headers.push_back(make_pair(name_, value_)); + return result; +} + +// +// WebRequestRemoveResponseHeaderAction +// + +WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction( + const std::string& name, + const std::string& value, + bool has_value) + : name_(name), + value_(value), + has_value_(has_value) { +} + +WebRequestRemoveResponseHeaderAction::~WebRequestRemoveResponseHeaderAction() {} + +int WebRequestRemoveResponseHeaderAction::GetStages() const { + return ON_HEADERS_RECEIVED; +} + +WebRequestAction::Type +WebRequestRemoveResponseHeaderAction::GetType() const { + return WebRequestAction::ACTION_REMOVE_RESPONSE_HEADER; +} + +LinkedPtrEventResponseDelta +WebRequestRemoveResponseHeaderAction::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)); + net::HttpResponseHeaders* headers = + optional_request_data.original_response_headers; + if (!headers) + return result; + void* iter = NULL; + std::string current_value; + while (headers->EnumerateHeader(&iter, name_, ¤t_value)) { + if (has_value_ && + (current_value.size() != value_.size() || + !std::equal(current_value.begin(), current_value.end(), + value_.begin(), + base::CaseInsensitiveCompare<char>()))) { + continue; + } + result->deleted_response_headers.push_back(make_pair(name_, current_value)); + } + return result; +} + +// // WebRequestIgnoreRulesAction // @@ -445,6 +583,7 @@ int WebRequestIgnoreRulesAction::GetMinimumPriority() const { LinkedPtrEventResponseDelta WebRequestIgnoreRulesAction::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()); diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h index 73f37f5..5c8a6cb 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.h @@ -13,6 +13,7 @@ #include "base/compiler_specific.h" #include "base/memory/linked_ptr.h" #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/common/extensions/api/events.h" #include "googleurl/src/gurl.h" @@ -48,6 +49,8 @@ class WebRequestAction { ACTION_REDIRECT_TO_EMPTY_DOCUMENT, ACTION_SET_REQUEST_HEADER, ACTION_REMOVE_REQUEST_HEADER, + ACTION_ADD_RESPONSE_HEADER, + ACTION_REMOVE_RESPONSE_HEADER, ACTION_IGNORE_RULES, }; @@ -80,6 +83,7 @@ class WebRequestAction { 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 = 0; }; @@ -109,6 +113,7 @@ class WebRequestActionSet { std::list<LinkedPtrEventResponseDelta> CreateDeltas( net::URLRequest* request, RequestStages request_stage, + const WebRequestRule::OptionalRequestData& optional_request_data, const std::string& extension_id, const base::Time& extension_install_time) const; @@ -140,6 +145,7 @@ class WebRequestCancelAction : public WebRequestAction { 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; @@ -159,6 +165,7 @@ class WebRequestRedirectAction : public WebRequestAction { 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; @@ -180,6 +187,7 @@ class WebRequestRedirectToTransparentImageAction : public WebRequestAction { 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; @@ -200,6 +208,7 @@ class WebRequestRedirectToEmptyDocumentAction : public WebRequestAction { 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; @@ -220,6 +229,7 @@ class WebRequestSetRequestHeaderAction : public WebRequestAction { 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; @@ -241,6 +251,7 @@ class WebRequestRemoveRequestHeaderAction : public WebRequestAction { 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; @@ -249,6 +260,54 @@ class WebRequestRemoveRequestHeaderAction : public WebRequestAction { DISALLOW_COPY_AND_ASSIGN(WebRequestRemoveRequestHeaderAction); }; +// Action that instructs to add a response header. +class WebRequestAddResponseHeaderAction : public WebRequestAction { + public: + WebRequestAddResponseHeaderAction(const std::string& name, + const std::string& value); + virtual ~WebRequestAddResponseHeaderAction(); + + // 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: + std::string name_; + std::string value_; + DISALLOW_COPY_AND_ASSIGN(WebRequestAddResponseHeaderAction); +}; + +// Action that instructs to remove a response header. +class WebRequestRemoveResponseHeaderAction : public WebRequestAction { + public: + explicit WebRequestRemoveResponseHeaderAction(const std::string& name, + const std::string& value, + bool has_value); + virtual ~WebRequestRemoveResponseHeaderAction(); + + // 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: + std::string name_; + std::string value_; + bool has_value_; + DISALLOW_COPY_AND_ASSIGN(WebRequestRemoveResponseHeaderAction); +}; + // Action that instructs to ignore rules below a certain priority. class WebRequestIgnoreRulesAction : public WebRequestAction { public: @@ -262,6 +321,7 @@ class WebRequestIgnoreRulesAction : public WebRequestAction { 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; @@ -271,7 +331,7 @@ class WebRequestIgnoreRulesAction : public WebRequestAction { }; // TODO(battre) Implement further actions: -// Redirect to constant url, Redirect by RegEx, Set header, Remove header, ... +// Redirect by RegEx, Cookie manipulations, ... } // namespace extensions diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc index ea51728..a6d2a6c 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.cc @@ -20,6 +20,8 @@ const char kUrlKey[] = "url"; const char kValueKey[] = "value"; // Values of dictionaries, in particular instance types +const char kAddResponseHeaderType[] = + "declarativeWebRequest.AddResponseHeader"; const char kCancelRequestType[] = "declarativeWebRequest.CancelRequest"; const char kIgnoreRulesType[] = "declarativeWebRequest.IgnoreRules"; const char kRedirectRequestType[] = "declarativeWebRequest.RedirectRequest"; @@ -29,6 +31,8 @@ const char kRedirectToTransparentImageType[] = "declarativeWebRequest.RedirectToTransparentImage"; const char kRemoveRequestHeaderType[] = "declarativeWebRequest.RemoveRequestHeader"; +const char kRemoveResponseHeaderType[] = + "declarativeWebRequest.RemoveResponseHeader"; const char kRequestMatcherType[] = "declarativeWebRequest.RequestMatcher"; const char kSetRequestHeaderType[] = "declarativeWebRequest.SetRequestHeader"; diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h index 14fb873..86984d0 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h @@ -24,12 +24,14 @@ extern const char kUrlKey[]; extern const char kValueKey[]; // Values of dictionaries, in particular instance types +extern const char kAddResponseHeaderType[]; extern const char kCancelRequestType[]; extern const char kIgnoreRulesType[]; extern const char kRedirectRequestType[]; extern const char kRedirectToEmptyDocumentType[]; extern const char kRedirectToTransparentImageType[]; extern const char kRemoveRequestHeaderType[]; +extern const char kRemoveResponseHeaderType[]; extern const char kRequestMatcherType[]; extern const char kSetRequestHeaderType[]; diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc index cac8386..1fc8e40 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.cc @@ -87,9 +87,10 @@ scoped_ptr<WebRequestRule> WebRequestRule::Create( std::list<LinkedPtrEventResponseDelta> WebRequestRule::CreateDeltas( net::URLRequest* request, - RequestStages request_stage) const { - return actions_->CreateDeltas(request, request_stage, id_.first, - extension_installation_time_); + RequestStages request_stage, + const OptionalRequestData& optional_request_data) const { + return actions_->CreateDeltas(request, request_stage, optional_request_data, + id_.first, extension_installation_time_); } int WebRequestRule::GetMinimumPriority() const { diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h index 5187688..d12e2fc 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h @@ -25,6 +25,7 @@ struct EventResponseDelta; } namespace net { +class HttpResponseHeaders; class URLRequest; } @@ -41,6 +42,13 @@ class WebRequestRule { typedef std::pair<ExtensionId, RuleId> GlobalRuleId; typedef int Priority; + // Container to pass additional information about requests that are not + // available in all request stages. + struct OptionalRequestData { + OptionalRequestData() : original_response_headers(NULL) {} + net::HttpResponseHeaders* original_response_headers; + }; + WebRequestRule(const GlobalRuleId& id, base::Time extension_installation_time, scoped_ptr<WebRequestConditionSet> conditions, @@ -64,7 +72,8 @@ class WebRequestRule { std::list<LinkedPtrEventResponseDelta> CreateDeltas( net::URLRequest* request, - RequestStages request_stage) const; + RequestStages request_stage, + const OptionalRequestData& optional_request_data) const; // Returns the minimum priority of rules that may be evaluated after // this rule. Defaults to MAX_INT. Only valid if the conditions of this rule diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc index 2da96a7..ea2869a 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc @@ -43,7 +43,8 @@ WebRequestRulesRegistry::GetMatches(net::URLRequest* request, std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( net::URLRequest* request, - RequestStages request_stage) { + RequestStages request_stage, + const WebRequestRule::OptionalRequestData& optional_request_data) { std::set<WebRequestRule::GlobalRuleId> matches = GetMatches(request, request_stage); @@ -93,7 +94,7 @@ std::list<LinkedPtrEventResponseDelta> WebRequestRulesRegistry::CreateDeltas( continue; std::list<LinkedPtrEventResponseDelta> rule_result = - rule->CreateDeltas(request, request_stage); + rule->CreateDeltas(request, request_stage, optional_request_data); result.splice(result.begin(), rule_result); min_priorities[extension_id] = std::max(current_min_priority, diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h index 3beff8f..b71406f 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h @@ -33,7 +33,6 @@ class URLRequest; namespace extensions { class RulesRegistryService; -class WebRequestRule; // The WebRequestRulesRegistry is responsible for managing // the internal representation of rules for the Declarative Web Request API. @@ -76,7 +75,9 @@ class WebRequestRulesRegistry : public RulesRegistryWithCache { // Returns which modifications should be executed on the network request // according to the rules registered in this registry. std::list<LinkedPtrEventResponseDelta> CreateDeltas( - net::URLRequest* request, RequestStages request_stage); + net::URLRequest* request, + RequestStages request_stage, + const WebRequestRule::OptionalRequestData& optional_request_data); // Implementation of RulesRegistryWithCache: virtual std::string AddRulesImpl( diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc index 9020ed5..7d322b4 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc @@ -336,7 +336,8 @@ TEST_F(WebRequestRulesRegistryTest, Precedences) { GURL url("http://www.google.com"); TestURLRequest request(url, NULL); std::list<LinkedPtrEventResponseDelta> deltas = - registry->CreateDeltas(&request, ON_BEFORE_REQUEST); + registry->CreateDeltas(&request, ON_BEFORE_REQUEST, + WebRequestRule::OptionalRequestData()); // The second extension is installed later and will win for this reason // in conflict resolution. @@ -382,7 +383,8 @@ TEST_F(WebRequestRulesRegistryTest, Priorities) { GURL url("http://www.google.com/index.html"); TestURLRequest request(url, NULL); std::list<LinkedPtrEventResponseDelta> deltas = - registry->CreateDeltas(&request, ON_BEFORE_REQUEST); + registry->CreateDeltas(&request, ON_BEFORE_REQUEST, + WebRequestRule::OptionalRequestData()); // The redirect by the first extension is ignored due to the ignore rule. ASSERT_EQ(1u, deltas.size()); diff --git a/chrome/browser/extensions/api/web_request/web_request_api.cc b/chrome/browser/extensions/api/web_request/web_request_api.cc index e91e8e9..5a73e14 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api.cc @@ -16,6 +16,7 @@ #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_content_browser_client.h" +#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rule.h" #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h" #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h" #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" @@ -488,7 +489,7 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest( bool initialize_blocked_requests = false; initialize_blocked_requests |= - ProcessDeclarativeRules(request, extensions::ON_BEFORE_REQUEST); + ProcessDeclarativeRules(request, extensions::ON_BEFORE_REQUEST, NULL); int extra_info_spec = 0; std::vector<const EventListener*> listeners = @@ -536,7 +537,8 @@ int ExtensionWebRequestEventRouter::OnBeforeSendHeaders( bool initialize_blocked_requests = false; initialize_blocked_requests |= - ProcessDeclarativeRules(request, extensions::ON_BEFORE_SEND_HEADERS); + ProcessDeclarativeRules(request, extensions::ON_BEFORE_SEND_HEADERS, + NULL); int extra_info_spec = 0; std::vector<const EventListener*> listeners = @@ -616,40 +618,54 @@ int ExtensionWebRequestEventRouter::OnHeadersReceived( if (!profile || helpers::HideRequestForURL(request->url())) return net::OK; + bool initialize_blocked_requests = false; + + initialize_blocked_requests |= + ProcessDeclarativeRules(request, extensions::ON_HEADERS_RECEIVED, + original_response_headers); + int extra_info_spec = 0; std::vector<const EventListener*> listeners = GetMatchingListeners(profile, extension_info_map, keys::kOnHeadersReceived, request, &extra_info_spec); - if (listeners.empty()) - return net::OK; - - if (GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) - return net::OK; + if (!listeners.empty() && + !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) { + ListValue args; + DictionaryValue* dict = new DictionaryValue(); + ExtractRequestInfo(request, dict); + dict->SetString(keys::kStatusLineKey, + original_response_headers->GetStatusLine()); + if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) { + dict->Set(keys::kResponseHeadersKey, + GetResponseHeadersList(original_response_headers)); + } + args.Append(dict); - ListValue args; - DictionaryValue* dict = new DictionaryValue(); - ExtractRequestInfo(request, dict); - dict->SetString(keys::kStatusLineKey, - original_response_headers->GetStatusLine()); - if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) { - dict->Set(keys::kResponseHeadersKey, - GetResponseHeadersList(original_response_headers)); + initialize_blocked_requests |= + DispatchEvent(profile, request, listeners, args); } - args.Append(dict); - if (DispatchEvent(profile, request, listeners, args)) { - blocked_requests_[request->identifier()].event = kOnHeadersReceived; - blocked_requests_[request->identifier()].callback = callback; - blocked_requests_[request->identifier()].net_log = &request->net_log(); - blocked_requests_[request->identifier()].override_response_headers = - override_response_headers; - blocked_requests_[request->identifier()].original_response_headers = - original_response_headers; + if (!initialize_blocked_requests) + return net::OK; // Nobody saw a reason for modifying the request. + + blocked_requests_[request->identifier()].event = kOnHeadersReceived; + blocked_requests_[request->identifier()].callback = callback; + blocked_requests_[request->identifier()].net_log = &request->net_log(); + blocked_requests_[request->identifier()].override_response_headers = + override_response_headers; + blocked_requests_[request->identifier()].original_response_headers = + original_response_headers; + + if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) { + // If there are no blocking handlers, only the declarative rules tried + // to modify the request and we can respond synchronously. + return ExecuteDeltas(profile, request->identifier(), + false /* call_callback*/); + } else { return net::ERR_IO_PENDING; } - return net::OK; } net::NetworkDelegate::AuthRequiredResponse @@ -1384,7 +1400,8 @@ int ExtensionWebRequestEventRouter::ExecuteDeltas( bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules( net::URLRequest* request, - extensions::RequestStages request_stage) { + extensions::RequestStages request_stage, + net::HttpResponseHeaders* original_response_headers) { if (!rules_registry_.get()) return false; @@ -1393,8 +1410,12 @@ bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules( // TODO(battre): Annotate deltas with extension IDs, so that we can // - Sort deltas by precedence // - Check whether extensions have host permissions. + extensions::WebRequestRule::OptionalRequestData optional_request_data; + optional_request_data.original_response_headers = + original_response_headers; std::list<linked_ptr<helpers::EventResponseDelta> > result = - rules_registry_->CreateDeltas(request, request_stage); + rules_registry_->CreateDeltas(request, request_stage, + optional_request_data); base::TimeDelta elapsed_time = start - base::Time::Now(); UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay", diff --git a/chrome/browser/extensions/api/web_request/web_request_api.h b/chrome/browser/extensions/api/web_request/web_request_api.h index ee7adf3..846381c 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api.h +++ b/chrome/browser/extensions/api/web_request/web_request_api.h @@ -330,10 +330,13 @@ class ExtensionWebRequestEventRouter { // Evaluates the rules of the declarative webrequest API and stores // modifications to the request that result from WebRequestActions as - // deltas in |blocked_requests_|. Returns whether any deltas were - // generated. - bool ProcessDeclarativeRules(net::URLRequest* request, - extensions::RequestStages request_stage); + // deltas in |blocked_requests_|. |original_response_headers| should only be + // set for the OnHeadersReceived stage and NULL otherwise. Returns whether any + // deltas were generated. + bool ProcessDeclarativeRules( + net::URLRequest* request, + extensions::RequestStages request_stage, + net::HttpResponseHeaders* original_response_headers); // Sets the flag that |event_type| has been signaled for |request_id|. // Returns the value of the flag before setting it. diff --git a/chrome/common/extensions/api/declarative_web_request.json b/chrome/common/extensions/api/declarative_web_request.json index 3e445d2..0ab3222 100644 --- a/chrome/common/extensions/api/declarative_web_request.json +++ b/chrome/common/extensions/api/declarative_web_request.json @@ -100,6 +100,45 @@ } }, { + "id": "declarativeWebRequest.AddResponseHeader", + "description": "Adds the response header to the response of this web request. As multiple response headers may share the same name, you need to first remove and then add a new response header in order to replace one.", + "type": "object", + "properties": { + "instanceType": { + "type": "string", "enum": ["declarativeWebRequest.AddResponseHeader"], + "nodoc": true + }, + "name": { + "type": "string", + "description": "HTTP response header name." + }, + "value": { + "type": "string", + "description": "HTTP response header value." + } + } + }, + { + "id": "declarativeWebRequest.RemoveResponseHeader", + "description": "Removes all response headers of the specified names and values.", + "type": "object", + "properties": { + "instanceType": { + "type": "string", "enum": ["declarativeWebRequest.RemoveResponseHeader"], + "nodoc": true + }, + "name": { + "type": "string", + "description": "HTTP request header name (case-insensitive)." + }, + "value": { + "type": "string", + "description": "HTTP request header value (case-insensitive).", + "optional": true + } + } + }, + { "id": "declarativeWebRequest.IgnoreRules", "description": "Masks all rules that match the specified criteria.", "type": "object", @@ -125,12 +164,14 @@ "supportsRules": true, "conditions": ["declarativeWebRequest.RequestMatcher"], "actions": [ + "declarativeWebRequest.AddResponseHeader", "declarativeWebRequest.CancelRequest", "declarativeWebRequest.RedirectRequest", "declarativeWebRequest.RedirectToTransparentImage", "declarativeWebRequest.RedirectToEmptyDocument", "declarativeWebRequest.SetRequestHeader", "declarativeWebRequest.RemoveRequestHeader", + "declarativeWebRequest.RemoveResponseHeader", "declarativeWebRequest.IgnoreRules" ] } diff --git a/chrome/common/extensions/docs/declarativeWebRequest.html b/chrome/common/extensions/docs/declarativeWebRequest.html index 65ee70d..07d2697 100644 --- a/chrome/common/extensions/docs/declarativeWebRequest.html +++ b/chrome/common/extensions/docs/declarativeWebRequest.html @@ -251,6 +251,14 @@ <ol> </ol> </li><li> + <a href="#type-declarativeWebRequest.AddResponseHeader">declarativeWebRequest.AddResponseHeader</a> + <ol> + </ol> + </li><li> + <a href="#type-declarativeWebRequest.RemoveResponseHeader">declarativeWebRequest.RemoveResponseHeader</a> + <ol> + </ol> + </li><li> <a href="#type-declarativeWebRequest.IgnoreRules">declarativeWebRequest.IgnoreRules</a> <ol> </ol> @@ -420,6 +428,15 @@ very fast URL matching algorithm for hundreds of thousands of URLs. <div> <div> <dt> + <a href="declarativeWebRequest.html#type-declarativeWebRequest.AddResponseHeader">declarativeWebRequest.AddResponseHeader</a> + </dt> + <dd class="todo"> + Undocumented. + </dd> + </div> + </div><div> + <div> + <dt> <a>declarativeWebRequest.CancelRequest</a> </dt> </div> @@ -468,6 +485,15 @@ very fast URL matching algorithm for hundreds of thousands of URLs. </div><div> <div> <dt> + <a href="declarativeWebRequest.html#type-declarativeWebRequest.RemoveResponseHeader">declarativeWebRequest.RemoveResponseHeader</a> + </dt> + <dd class="todo"> + Undocumented. + </dd> + </div> + </div><div> + <div> + <dt> <a href="declarativeWebRequest.html#type-declarativeWebRequest.IgnoreRules">declarativeWebRequest.IgnoreRules</a> </dt> <dd class="todo"> @@ -915,6 +941,157 @@ very fast URL matching algorithm for hundreds of thousands of URLs. <!-- FUNCTION PARAMETERS --> </div> </div><div class="apiItem"> + <a name="type-declarativeWebRequest.AddResponseHeader"></a> + <h4>declarativeWebRequest.AddResponseHeader</h4> + <div> + <dt> + <em> + <!-- TYPE --> + <div style="display:inline"> + ( + <span id="typeTemplate"> + <span> + <span>object</span> + </span> + </span> + ) + </div> + </em> + </dt> + <dd>Adds the response header to the response of this web request. As multiple response headers may share the same name, you need to first remove and then add a new response header in order to replace one.</dd> + <!-- OBJECT PROPERTIES --> + <dd> + <dl> + <div> + <div> + <dt> + <var>name</var> + <em> + <!-- TYPE --> + <div style="display:inline"> + ( + <span id="typeTemplate"> + <span> + <span>string</span> + </span> + </span> + ) + </div> + </em> + </dt> + <dd>HTTP response header name.</dd> + <!-- OBJECT PROPERTIES --> + <!-- OBJECT METHODS --> + <!-- OBJECT EVENT FIELDS --> + <!-- FUNCTION PARAMETERS --> + </div> + </div><div> + <div> + <dt> + <var>value</var> + <em> + <!-- TYPE --> + <div style="display:inline"> + ( + <span id="typeTemplate"> + <span> + <span>string</span> + </span> + </span> + ) + </div> + </em> + </dt> + <dd>HTTP response header value.</dd> + <!-- OBJECT PROPERTIES --> + <!-- OBJECT METHODS --> + <!-- OBJECT EVENT FIELDS --> + <!-- FUNCTION PARAMETERS --> + </div> + </div> + </dl> + </dd> + <!-- OBJECT METHODS --> + <!-- OBJECT EVENT FIELDS --> + <!-- FUNCTION PARAMETERS --> + </div> + </div><div class="apiItem"> + <a name="type-declarativeWebRequest.RemoveResponseHeader"></a> + <h4>declarativeWebRequest.RemoveResponseHeader</h4> + <div> + <dt> + <em> + <!-- TYPE --> + <div style="display:inline"> + ( + <span id="typeTemplate"> + <span> + <span>object</span> + </span> + </span> + ) + </div> + </em> + </dt> + <dd>Removes all response headers of the specified names and values.</dd> + <!-- OBJECT PROPERTIES --> + <dd> + <dl> + <div> + <div> + <dt> + <var>name</var> + <em> + <!-- TYPE --> + <div style="display:inline"> + ( + <span id="typeTemplate"> + <span> + <span>string</span> + </span> + </span> + ) + </div> + </em> + </dt> + <dd>HTTP request header name (case-insensitive).</dd> + <!-- OBJECT PROPERTIES --> + <!-- OBJECT METHODS --> + <!-- OBJECT EVENT FIELDS --> + <!-- FUNCTION PARAMETERS --> + </div> + </div><div> + <div> + <dt> + <var>value</var> + <em> + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional">optional</span> + <span id="typeTemplate"> + <span> + <span>string</span> + </span> + </span> + ) + </div> + </em> + </dt> + <dd>HTTP request header value (case-insensitive).</dd> + <!-- OBJECT PROPERTIES --> + <!-- OBJECT METHODS --> + <!-- OBJECT EVENT FIELDS --> + <!-- FUNCTION PARAMETERS --> + </div> + </div> + </dl> + </dd> + <!-- OBJECT METHODS --> + <!-- OBJECT EVENT FIELDS --> + <!-- FUNCTION PARAMETERS --> + </div> + </div><div class="apiItem"> <a name="type-declarativeWebRequest.IgnoreRules"></a> <h4>declarativeWebRequest.IgnoreRules</h4> <div> diff --git a/chrome/renderer/resources/extensions/declarative_webrequest_custom_bindings.js b/chrome/renderer/resources/extensions/declarative_webrequest_custom_bindings.js index 4d4db1a..5a8d798 100644 --- a/chrome/renderer/resources/extensions/declarative_webrequest_custom_bindings.js +++ b/chrome/renderer/resources/extensions/declarative_webrequest_custom_bindings.js @@ -48,6 +48,12 @@ chromeHidden.registerCustomHook('declarativeWebRequest', function(api) { chrome.declarativeWebRequest.RemoveRequestHeader = function(parameters) { setupInstance(this, parameters, 'RemoveRequestHeader'); }; + chrome.declarativeWebRequest.AddResponseHeader = function(parameters) { + setupInstance(this, parameters, 'AddResponseHeader'); + }; + chrome.declarativeWebRequest.RemoveResponseHeader = function(parameters) { + setupInstance(this, parameters, 'RemoveResponseHeader'); + }; chrome.declarativeWebRequest.RedirectToTransparentImage = function(parameters) { setupInstance(this, parameters, 'RedirectToTransparentImage'); 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 be22dd6..e6e621f 100644 --- a/chrome/test/data/extensions/api_test/webrequest/test_declarative.js +++ b/chrome/test/data/extensions/api_test/webrequest/test_declarative.js @@ -3,6 +3,8 @@ // found in the LICENSE file. var onRequest = chrome.declarativeWebRequest.onRequest; +var AddResponseHeader = + chrome.declarativeWebRequest.AddResponseHeader; var RequestMatcher = chrome.declarativeWebRequest.RequestMatcher; var CancelRequest = chrome.declarativeWebRequest.CancelRequest; var RedirectRequest = chrome.declarativeWebRequest.RedirectRequest; @@ -14,6 +16,8 @@ var SetRequestHeader = chrome.declarativeWebRequest.SetRequestHeader; var RemoveRequestHeader = chrome.declarativeWebRequest.RemoveRequestHeader; +var RemoveResponseHeader = + chrome.declarativeWebRequest.RemoveResponseHeader; var IgnoreRules = chrome.declarativeWebRequest.IgnoreRules; @@ -36,6 +40,10 @@ function getURLHttpRedirectTest() { "files/extensions/api_test/webrequest/declarative/a.html"); } +function getURLSetCookie() { + return getServerURL('set-cookie?Foo=Bar'); +} + runTests([ function testCancelRequest() { ignoreUnexpected = true; @@ -222,6 +230,49 @@ runTests([ }); }, + function testAddResponseHeader() { + ignoreUnexpected = true; + expect(); // Used for initialization. + onRequest.addRules( + [{conditions: [new RequestMatcher()], + actions: [new AddResponseHeader({name: "Set-Cookie", value: "Bar=baz"})] + }], + function() { + navigateAndWait(getURLEchoUserAgent(), function() { + chrome.test.listenOnce(chrome.extension.onRequest, function(request) { + chrome.test.assertTrue(request.pass, "Cookie was not added."); + }); + chrome.tabs.executeScript(tabId, + { + code: "chrome.extension.sendRequest(" + + "{pass: document.cookie.indexOf('Bar') != -1});" + }); + }); + }); + }, + + function testRemoveResponseHeader() { + ignoreUnexpected = true; + expect(); // Used for initialization. + onRequest.addRules( + [{conditions: [new RequestMatcher()], + actions: [new RemoveResponseHeader({name: "Set-Cookie", + value: "FoO=bAR"})] + }], + function() { + navigateAndWait(getURLSetCookie(), function() { + chrome.test.listenOnce(chrome.extension.onRequest, function(request) { + chrome.test.assertTrue(request.pass, "Cookie was not removed."); + }); + chrome.tabs.executeScript(tabId, + { + code: "chrome.extension.sendRequest(" + + "{pass: document.cookie.indexOf('Foo') == -1});" + }); + }); + }); + }, + function testPriorities() { ignoreUnexpected = true; expect( |