Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Side by Side Diff: chrome/browser/extensions/api/declarative_webrequest/webrequest_action.cc

Issue 10449069: Support redirects by regular expression in declarative WebRequest API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action .h" 5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_action .h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
12 #include "base/string_util.h" 12 #include "base/string_util.h"
13 #include "base/utf_string_conversions.h"
13 #include "base/values.h" 14 #include "base/values.h"
14 #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h" 15 #include "chrome/browser/extensions/api/declarative_webrequest/request_stages.h"
15 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_consta nts.h" 16 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_consta nts.h"
16 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 17 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
17 #include "net/url_request/url_request.h" 18 #include "net/url_request/url_request.h"
18 19
19 namespace extensions { 20 namespace extensions {
20 21
21 namespace keys = declarative_webrequest_constants; 22 namespace keys = declarative_webrequest_constants;
22 23
(...skipping 28 matching lines...) Expand all
51 std::string* error, 52 std::string* error,
52 bool* bad_message) { 53 bool* bad_message) {
53 std::string redirect_url_string; 54 std::string redirect_url_string;
54 INPUT_FORMAT_VALIDATE( 55 INPUT_FORMAT_VALIDATE(
55 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string)); 56 dict->GetString(keys::kRedirectUrlKey, &redirect_url_string));
56 GURL redirect_url(redirect_url_string); 57 GURL redirect_url(redirect_url_string);
57 return scoped_ptr<WebRequestAction>( 58 return scoped_ptr<WebRequestAction>(
58 new WebRequestRedirectAction(redirect_url)); 59 new WebRequestRedirectAction(redirect_url));
59 } 60 }
60 61
62 scoped_ptr<WebRequestAction> CreateRedirectRequestByRegExAction(
63 const base::DictionaryValue* dict,
64 std::string* error,
65 bool* bad_message) {
66 std::string from;
67 std::string to;
68 bool use_perl_capture_group_style = false;
69 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kFromKey, &from));
70 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kToKey, &to));
71 if (dict->HasKey(keys::kPerlCaptureGroupStyleKey)) {
72 INPUT_FORMAT_VALIDATE(dict->GetBoolean(keys::kPerlCaptureGroupStyleKey,
73 &use_perl_capture_group_style));
74 }
75
76 // TODO(battre): Invert this once we use RE2.
77 if (!use_perl_capture_group_style)
78 to = WebRequestRedirectByRegExAction::Re2ToPerlStyle(to);
79
80 UParseError parse_error;
81 UErrorCode status = U_ZERO_ERROR;
82 scoped_ptr<icu::RegexPattern> pattern(
83 icu::RegexPattern::compile(icu::UnicodeString(from.data(), from.size()),
84 0, parse_error, status));
85 if (U_FAILURE(status) || !pattern.get()) {
86 *error = "Invalid pattern '" + from + "' -> '" + to + "'";
87 return scoped_ptr<WebRequestAction>(NULL);
88 }
89 return scoped_ptr<WebRequestAction>(
90 new WebRequestRedirectByRegExAction(pattern.Pass(), to));
91 }
92
61 scoped_ptr<WebRequestAction> CreateSetRequestHeaderAction( 93 scoped_ptr<WebRequestAction> CreateSetRequestHeaderAction(
62 const base::DictionaryValue* dict, 94 const base::DictionaryValue* dict,
63 std::string* error, 95 std::string* error,
64 bool* bad_message) { 96 bool* bad_message) {
65 std::string name; 97 std::string name;
66 std::string value; 98 std::string value;
67 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name)); 99 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kNameKey, &name));
68 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value)); 100 INPUT_FORMAT_VALIDATE(dict->GetString(keys::kValueKey, &value));
69 return scoped_ptr<WebRequestAction>( 101 return scoped_ptr<WebRequestAction>(
70 new WebRequestSetRequestHeaderAction(name, value)); 102 new WebRequestSetRequestHeaderAction(name, value));
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 (* FactoryMethod)(const base::DictionaryValue* /* dict */ , 157 (* FactoryMethod)(const base::DictionaryValue* /* dict */ ,
126 std::string* /* error */, 158 std::string* /* error */,
127 bool* /* bad_message */); 159 bool* /* bad_message */);
128 std::map<std::string, FactoryMethod> factory_methods; 160 std::map<std::string, FactoryMethod> factory_methods;
129 161
130 WebRequestActionFactory() { 162 WebRequestActionFactory() {
131 factory_methods[keys::kAddResponseHeaderType] = 163 factory_methods[keys::kAddResponseHeaderType] =
132 &CreateAddResponseHeaderAction; 164 &CreateAddResponseHeaderAction;
133 factory_methods[keys::kCancelRequestType] = 165 factory_methods[keys::kCancelRequestType] =
134 &CallConstructorFactoryMethod<WebRequestCancelAction>; 166 &CallConstructorFactoryMethod<WebRequestCancelAction>;
167 factory_methods[keys::kRedirectByRegExType] =
168 &CreateRedirectRequestByRegExAction;
135 factory_methods[keys::kRedirectRequestType] = 169 factory_methods[keys::kRedirectRequestType] =
136 &CreateRedirectRequestAction; 170 &CreateRedirectRequestAction;
137 factory_methods[keys::kRedirectToTransparentImageType] = 171 factory_methods[keys::kRedirectToTransparentImageType] =
138 &CallConstructorFactoryMethod< 172 &CallConstructorFactoryMethod<
139 WebRequestRedirectToTransparentImageAction>; 173 WebRequestRedirectToTransparentImageAction>;
140 factory_methods[keys::kRedirectToEmptyDocumentType] = 174 factory_methods[keys::kRedirectToEmptyDocumentType] =
141 &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>; 175 &CallConstructorFactoryMethod<WebRequestRedirectToEmptyDocumentAction>;
142 factory_methods[keys::kSetRequestHeaderType] = 176 factory_methods[keys::kSetRequestHeaderType] =
143 &CreateSetRequestHeaderAction; 177 &CreateSetRequestHeaderAction;
144 factory_methods[keys::kRemoveRequestHeaderType] = 178 factory_methods[keys::kRemoveRequestHeaderType] =
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 const base::Time& extension_install_time) const { 411 const base::Time& extension_install_time) const {
378 CHECK(request_stage & GetStages()); 412 CHECK(request_stage & GetStages());
379 LinkedPtrEventResponseDelta result( 413 LinkedPtrEventResponseDelta result(
380 new extension_web_request_api_helpers::EventResponseDelta( 414 new extension_web_request_api_helpers::EventResponseDelta(
381 extension_id, extension_install_time)); 415 extension_id, extension_install_time));
382 result->new_url = GURL(kEmptyDocumentUrl); 416 result->new_url = GURL(kEmptyDocumentUrl);
383 return result; 417 return result;
384 } 418 }
385 419
386 // 420 //
421 // WebRequestRedirectByRegExAction
422 //
423
424 WebRequestRedirectByRegExAction::WebRequestRedirectByRegExAction(
425 scoped_ptr<icu::RegexPattern> from_pattern,
426 const std::string& to_pattern)
427 : from_pattern_(from_pattern.Pass()),
428 to_pattern_(to_pattern.data(), to_pattern.size()) {}
429
430 WebRequestRedirectByRegExAction::~WebRequestRedirectByRegExAction() {}
431
432 // About the syntax of the two languages:
433 //
434 // ICU (Perl) states:
435 // $n The text of capture group n will be substituted for $n. n must be >= 0
436 // and not greater than the number of capture groups. A $ not followed by a
437 // digit has no special meaning, and will appear in the substitution text
438 // as itself, a $.
439 // \ Treat the following character as a literal, suppressing any special
440 // meaning. Backslash escaping in substitution text is only required for
441 // '$' and '\', but may be used on any other character without bad effects.
442 //
443 // RE2, derived from RE2::Rewrite()
444 // \ May only be followed by a digit or another \. If followed by a single
445 // digit, both characters represent the respective capture group. If followed
446 // by another \, it is used as an escape sequence.
447
448 // static
449 std::string WebRequestRedirectByRegExAction::PerlToRe2Style(
450 const std::string& perl) {
451 std::string::const_iterator i = perl.begin();
452 std::string result;
453 while (i != perl.end()) {
454 if (*i == '$') {
455 ++i;
456 if (i == perl.end()) {
457 result += '$';
458 } else if (isdigit(*i)) {
459 result += '\\';
460 result += *i;
461 } else {
462 result += '$';
463 result += *i;
464 }
465 } else if (*i == '\\') {
466 ++i;
467 if (i == perl.end()) {
468 result += '\\';
469 } else if (*i == '$'){
470 result += '$';
471 } else if (*i == '\\'){
472 result += "\\\\";
473 } else {
474 result += *i;
475 }
476 } else {
477 result += *i;
478 }
479 ++i;
480 }
481 return result;
482 }
483
484 // static
485 std::string WebRequestRedirectByRegExAction::Re2ToPerlStyle(
486 const std::string& re2) {
487 std::string::const_iterator i = re2.begin();
488 std::string result;
489 while (i != re2.end()) {
490 if (*i == '\\') {
491 ++i;
492 if (i == re2.end()) {
493 result += '\\'; // Illegal, treat as best effort.
494 } else if (isdigit(*i)) {
495 result += '$';
496 result += *i;
497 } else if (*i == '\\') {
498 result += "\\\\";
499 } else { // Illegal, treat as best effort.
500 result += '\\';
501 result += *i;
502 }
503 } else {
504 result += *i;
505 }
506 ++i;
507 }
508 return result;
509 }
510
511 int WebRequestRedirectByRegExAction::GetStages() const {
512 return ON_BEFORE_REQUEST;
513 }
514
515 WebRequestAction::Type WebRequestRedirectByRegExAction::GetType() const {
516 return WebRequestAction::ACTION_REDIRECT_BY_REGEX_DOCUMENT;
517 }
518
519 LinkedPtrEventResponseDelta WebRequestRedirectByRegExAction::CreateDelta(
520 net::URLRequest* request,
521 RequestStages request_stage,
522 const WebRequestRule::OptionalRequestData& optional_request_data,
523 const std::string& extension_id,
524 const base::Time& extension_install_time) const {
525 CHECK(request_stage & GetStages());
526 CHECK(from_pattern_.get());
527
528 UErrorCode status = U_ZERO_ERROR;
529 const std::string& old_url = request->url().spec();
530 icu::UnicodeString old_url_unicode(old_url.data(), old_url.size());
531
532 scoped_ptr<icu::RegexMatcher> matcher(
533 from_pattern_->matcher(old_url_unicode, status));
534 if (U_FAILURE(status) || !matcher.get())
535 return LinkedPtrEventResponseDelta(NULL);
536
537 icu::UnicodeString new_url = matcher->replaceAll(to_pattern_, status);
538 if (U_FAILURE(status))
539 return LinkedPtrEventResponseDelta(NULL);
540
541 std::string new_url_utf8;
542 UTF16ToUTF8(new_url.getBuffer(), new_url.length(), &new_url_utf8);
543
544 if (new_url_utf8 == request->url().spec())
545 return LinkedPtrEventResponseDelta(NULL);
546
547 LinkedPtrEventResponseDelta result(
548 new extension_web_request_api_helpers::EventResponseDelta(
549 extension_id, extension_install_time));
550 result->new_url = GURL(new_url_utf8);
551 return result;
552 }
553
554 //
387 // WebRequestSetRequestHeaderAction 555 // WebRequestSetRequestHeaderAction
388 // 556 //
389 557
390 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction( 558 WebRequestSetRequestHeaderAction::WebRequestSetRequestHeaderAction(
391 const std::string& name, 559 const std::string& name,
392 const std::string& value) 560 const std::string& value)
393 : name_(name), 561 : name_(name),
394 value_(value) { 562 value_(value) {
395 } 563 }
396 564
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 } 646 }
479 647
480 LinkedPtrEventResponseDelta 648 LinkedPtrEventResponseDelta
481 WebRequestAddResponseHeaderAction::CreateDelta( 649 WebRequestAddResponseHeaderAction::CreateDelta(
482 net::URLRequest* request, 650 net::URLRequest* request,
483 RequestStages request_stage, 651 RequestStages request_stage,
484 const WebRequestRule::OptionalRequestData& optional_request_data, 652 const WebRequestRule::OptionalRequestData& optional_request_data,
485 const std::string& extension_id, 653 const std::string& extension_id,
486 const base::Time& extension_install_time) const { 654 const base::Time& extension_install_time) const {
487 CHECK(request_stage & GetStages()); 655 CHECK(request_stage & GetStages());
656 net::HttpResponseHeaders* headers =
657 optional_request_data.original_response_headers;
658 if (!headers)
659 return LinkedPtrEventResponseDelta(NULL);
660
661 // Don't generate the header if it exists already.
662 if (headers->HasHeaderValue(name_, value_))
663 return LinkedPtrEventResponseDelta(NULL);
664
488 LinkedPtrEventResponseDelta result( 665 LinkedPtrEventResponseDelta result(
489 new extension_web_request_api_helpers::EventResponseDelta( 666 new extension_web_request_api_helpers::EventResponseDelta(
490 extension_id, extension_install_time)); 667 extension_id, extension_install_time));
491
492 net::HttpResponseHeaders* headers =
493 optional_request_data.original_response_headers;
494 if (!headers)
495 return result;
496
497 // Don't generate the header if it exists already.
498 if (headers->HasHeaderValue(name_, value_))
499 return result;
500
501 result->added_response_headers.push_back(make_pair(name_, value_)); 668 result->added_response_headers.push_back(make_pair(name_, value_));
502 return result; 669 return result;
503 } 670 }
504 671
505 // 672 //
506 // WebRequestRemoveResponseHeaderAction 673 // WebRequestRemoveResponseHeaderAction
507 // 674 //
508 675
509 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction( 676 WebRequestRemoveResponseHeaderAction::WebRequestRemoveResponseHeaderAction(
510 const std::string& name, 677 const std::string& name,
(...skipping 16 matching lines...) Expand all
527 } 694 }
528 695
529 LinkedPtrEventResponseDelta 696 LinkedPtrEventResponseDelta
530 WebRequestRemoveResponseHeaderAction::CreateDelta( 697 WebRequestRemoveResponseHeaderAction::CreateDelta(
531 net::URLRequest* request, 698 net::URLRequest* request,
532 RequestStages request_stage, 699 RequestStages request_stage,
533 const WebRequestRule::OptionalRequestData& optional_request_data, 700 const WebRequestRule::OptionalRequestData& optional_request_data,
534 const std::string& extension_id, 701 const std::string& extension_id,
535 const base::Time& extension_install_time) const { 702 const base::Time& extension_install_time) const {
536 CHECK(request_stage & GetStages()); 703 CHECK(request_stage & GetStages());
704 net::HttpResponseHeaders* headers =
705 optional_request_data.original_response_headers;
706 if (!headers)
707 return LinkedPtrEventResponseDelta(NULL);
708
537 LinkedPtrEventResponseDelta result( 709 LinkedPtrEventResponseDelta result(
538 new extension_web_request_api_helpers::EventResponseDelta( 710 new extension_web_request_api_helpers::EventResponseDelta(
539 extension_id, extension_install_time)); 711 extension_id, extension_install_time));
540 net::HttpResponseHeaders* headers =
541 optional_request_data.original_response_headers;
542 if (!headers)
543 return result;
544 void* iter = NULL; 712 void* iter = NULL;
545 std::string current_value; 713 std::string current_value;
546 while (headers->EnumerateHeader(&iter, name_, &current_value)) { 714 while (headers->EnumerateHeader(&iter, name_, &current_value)) {
547 if (has_value_ && 715 if (has_value_ &&
548 (current_value.size() != value_.size() || 716 (current_value.size() != value_.size() ||
549 !std::equal(current_value.begin(), current_value.end(), 717 !std::equal(current_value.begin(), current_value.end(),
550 value_.begin(), 718 value_.begin(),
551 base::CaseInsensitiveCompare<char>()))) { 719 base::CaseInsensitiveCompare<char>()))) {
552 continue; 720 continue;
553 } 721 }
(...skipping 30 matching lines...) Expand all
584 net::URLRequest* request, 752 net::URLRequest* request,
585 RequestStages request_stage, 753 RequestStages request_stage,
586 const WebRequestRule::OptionalRequestData& optional_request_data, 754 const WebRequestRule::OptionalRequestData& optional_request_data,
587 const std::string& extension_id, 755 const std::string& extension_id,
588 const base::Time& extension_install_time) const { 756 const base::Time& extension_install_time) const {
589 CHECK(request_stage & GetStages()); 757 CHECK(request_stage & GetStages());
590 return LinkedPtrEventResponseDelta(NULL); 758 return LinkedPtrEventResponseDelta(NULL);
591 } 759 }
592 760
593 } // namespace extensions 761 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698