Chromium Code Reviews| Index: chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc |
| diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc |
| index 271afc1d9bbf284899aa2e65271fee9d1010156d..74368e173c7c6f630e8bb1098489e915be22c18b 100644 |
| --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc |
| +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc |
| @@ -10,6 +10,7 @@ |
| #include "base/logging.h" |
| #include "base/stringprintf.h" |
| #include "base/string_util.h" |
| +#include "base/utf_string_conversions.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" |
| @@ -58,6 +59,31 @@ scoped_ptr<WebRequestAction> CreateRedirectRequestAction( |
| new WebRequestRedirectAction(redirect_url)); |
| } |
| +scoped_ptr<WebRequestAction> CreateRedirectRequestByRegExAction( |
| + const base::DictionaryValue* dict, |
| + std::string* error, |
| + bool* bad_message) { |
| + std::string from; |
| + std::string to; |
| + INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from)); |
| + INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to)); |
| + |
| + // TODO(battre): Add this line once we migrate from ICU RegEx to RE2 RegEx.s |
| + // to = WebRequestRedirectByRegExAction::PerlToRe2Style(to); |
| + |
| + UParseError parse_error; |
| + UErrorCode status = U_ZERO_ERROR; |
| + scoped_ptr<icu::RegexPattern> pattern( |
| + icu::RegexPattern::compile(icu::UnicodeString(from.data(), from.size()), |
| + 0, parse_error, status)); |
| + if (U_FAILURE(status) || !pattern.get()) { |
| + *error = "Invalid pattern '" + from + "' -> '" + to + "'"; |
| + return scoped_ptr<WebRequestAction>(NULL); |
| + } |
| + return scoped_ptr<WebRequestAction>( |
| + new WebRequestRedirectByRegExAction(pattern.Pass(), to)); |
| +} |
| + |
| scoped_ptr<WebRequestAction> CreateSetRequestHeaderAction( |
| const base::DictionaryValue* dict, |
| std::string* error, |
| @@ -132,6 +158,8 @@ struct WebRequestActionFactory { |
| &CreateAddResponseHeaderAction; |
| factory_methods[keys::kCancelRequestType] = |
| &CallConstructorFactoryMethod<WebRequestCancelAction>; |
| + factory_methods[keys::kRedirectByRegExType] = |
| + &CreateRedirectRequestByRegExAction; |
| factory_methods[keys::kRedirectRequestType] = |
| &CreateRedirectRequestAction; |
| factory_methods[keys::kRedirectToTransparentImageType] = |
| @@ -384,6 +412,113 @@ WebRequestRedirectToEmptyDocumentAction::CreateDelta( |
| } |
| // |
| +// WebRequestRedirectByRegExAction |
| +// |
| + |
| +WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction( |
| + scoped_ptr<icu::RegexPattern> from_pattern, |
| + const std::string& to_pattern) |
| + : from_pattern_(from_pattern.Pass()), |
| + to_pattern_(to_pattern.data(), to_pattern.size()) {} |
| + |
| +WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {} |
| + |
| +// About the syntax of the two languages: |
| +// |
| +// ICU (Perl) states: |
| +// $n The text of capture group n will be substituted for $n. n must be >= 0 |
| +// and not greater than the number of capture groups. A $ not followed by a |
| +// digit has no special meaning, and will appear in the substitution text |
| +// as itself, a $. |
| +// \ Treat the following character as a literal, suppressing any special |
| +// meaning. Backslash escaping in substitution text is only required for |
| +// '$' and '\', but may be used on any other character without bad effects. |
| +// |
| +// RE2, derived from RE2::Rewrite() |
| +// \ May only be followed by a digit or another \. If followed by a single |
| +// digit, both characters represent the respective capture group. If followed |
| +// by another \, it is used as an escape sequence. |
| + |
| +// static |
| +std::string WebRequestRedirectByRegExAction::PerlToRe2Style( |
| + const std::string& perl) { |
| + std::string::const_iterator i = perl.begin(); |
| + std::string result; |
| + while (i != perl.end()) { |
| + if (*i == '$') { |
| + ++i; |
| + if (i == perl.end()) { |
| + result += '$'; |
| + } else if (isdigit(*i)) { |
| + result += '\\'; |
| + result += *i; |
| + } else { |
| + result += '$'; |
| + result += *i; |
| + } |
| + } else if (*i == '\\') { |
| + ++i; |
| + if (i == perl.end()) { |
| + result += '\\'; |
| + } else if (*i == '$'){ |
|
Matt Perry
2012/06/14 18:39:13
nit: space before {
|
| + result += '$'; |
| + } else if (*i == '\\'){ |
|
Matt Perry
2012/06/14 18:39:13
ditto
|
| + result += "\\\\"; |
| + } else { |
| + result += *i; |
| + } |
| + } else { |
| + result += *i; |
| + } |
| + ++i; |
| + } |
| + return result; |
| +} |
| + |
| +int WebRequestRedirectByRegExAction::GetStages() const { |
| + return ON_BEFORE_REQUEST; |
| +} |
| + |
| +WebRequestAction::Type WebRequestRedirectByRegExAction::GetType() const { |
| + return WebRequestAction::ACTION_REDIRECT_BY_REGEX_DOCUMENT; |
| +} |
| + |
| +LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::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()); |
| + CHECK(from_pattern_.get()); |
| + |
| + UErrorCode status = U_ZERO_ERROR; |
| + const std::string& old_url = request->url().spec(); |
| + icu::UnicodeString old_url_unicode(old_url.data(), old_url.size()); |
| + |
| + scoped_ptr<icu::RegexMatcher> matcher( |
| + from_pattern_->matcher(old_url_unicode, status)); |
| + if (U_FAILURE(status) || !matcher.get()) |
| + return LinkedPtrEventResponseDelta(NULL); |
| + |
| + icu::UnicodeString new_url = matcher->replaceAll(to_pattern_, status); |
| + if (U_FAILURE(status)) |
| + return LinkedPtrEventResponseDelta(NULL); |
| + |
| + std::string new_url_utf8; |
| + UTF16ToUTF8(new_url.getBuffer(), new_url.length(), &new_url_utf8); |
| + |
| + if (new_url_utf8 == request->url().spec()) |
| + return LinkedPtrEventResponseDelta(NULL); |
| + |
| + LinkedPtrEventResponseDelta result( |
| + new extension_web_request_api_helpers::EventResponseDelta( |
| + extension_id, extension_install_time)); |
| + result->new_url = GURL(new_url_utf8); |
| + return result; |
| +} |
| + |
| +// |
| // WebRequestSetRequestHeaderAction |
| // |
| @@ -485,19 +620,18 @@ WebRequestAddResponseHeaderAction::CreateDelta( |
| 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; |
| + return LinkedPtrEventResponseDelta(NULL); |
| // Don't generate the header if it exists already. |
| if (headers->HasHeaderValue(name_, value_)) |
| - return result; |
| + return LinkedPtrEventResponseDelta(NULL); |
| + LinkedPtrEventResponseDelta result( |
| + new extension_web_request_api_helpers::EventResponseDelta( |
| + extension_id, extension_install_time)); |
| result->added_response_headers.push_back(make_pair(name_, value_)); |
| return result; |
| } |
| @@ -534,13 +668,14 @@ WebRequestRemoveResponseHeaderAction::CreateDelta( |
| 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; |
| + return LinkedPtrEventResponseDelta(NULL); |
| + |
| + LinkedPtrEventResponseDelta result( |
| + new extension_web_request_api_helpers::EventResponseDelta( |
| + extension_id, extension_install_time)); |
| void* iter = NULL; |
| std::string current_value; |
| while (headers->EnumerateHeader(&iter, name_, ¤t_value)) { |