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

Unified Diff: chrome/browser/extensions/extension_webrequest_api_helpers.cc

Issue 8519003: More unittests for webRequest API and better conflict resolution (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improve merging of header modifications in webRequest.OnHeadersReceived Created 9 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_webrequest_api_helpers.cc
diff --git a/chrome/browser/extensions/extension_webrequest_api_helpers.cc b/chrome/browser/extensions/extension_webrequest_api_helpers.cc
index 06db3d238d06a91d45d41802158953c27d45eaa3..bbf4dc9b44b7f8224dcd50d66db78739950e5567 100644
--- a/chrome/browser/extensions/extension_webrequest_api_helpers.cc
+++ b/chrome/browser/extensions/extension_webrequest_api_helpers.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/extension_webrequest_api_helpers.h"
+#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_webrequest_api.h"
#include "net/http/http_util.h"
@@ -165,21 +166,46 @@ EventResponseDelta* CalculateOnHeadersReceivedDelta(
const std::string& extension_id,
const base::Time& extension_install_time,
bool cancel,
- const std::string& status_line,
- const std::string& response_headers_string) {
+ net::HttpResponseHeaders* old_response_headers,
+ ResponseHeaders* new_response_headers) {
EventResponseDelta* result =
new EventResponseDelta(extension_id, extension_install_time);
result->cancel = cancel;
- if (!response_headers_string.empty()) {
- std::string new_headers_string =
- status_line + "\n" + response_headers_string;
+ // Find deleted headers.
+ {
+ void* iter = NULL;
+ std::string name;
+ std::string value;
+ while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ ResponseHeader current_header(name, value);
+ if (std::find(new_response_headers->begin(),
+ new_response_headers->end(),
+ current_header) == new_response_headers->end()) {
+ result->deleted_response_headers.push_back(current_header);
+ }
+ }
+ }
- result->new_response_headers =
- new net::HttpResponseHeaders(
- net::HttpUtil::AssembleRawHeaders(new_headers_string.c_str(),
- new_headers_string.length()));
+ // Find added headers.
+ {
+ for (ResponseHeaders::const_iterator i = new_response_headers->begin();
+ i != new_response_headers->end(); ++i) {
+ bool header_found = false;
+ void* iter = NULL;
+ std::string name;
+ std::string value;
+ // We don't use HttpResponseHeaders::HasHeaderValue because it is
+ // case insensitive
+ while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value) &&
+ !header_found) {
+ header_found = (name == i->first) && (value == i->second);
+ }
+ if (!header_found)
+ result->added_response_headers.push_back(*i);
+ }
}
+
return result;
}
@@ -223,7 +249,7 @@ void MergeOnBeforeRequestResponses(
bool redirected = false;
for (delta = deltas.begin(); delta != deltas.end(); ++delta) {
if (!(*delta)->new_url.is_empty()) {
- if (!redirected) {
+ if (!redirected || *new_url == (*delta)->new_url) {
*new_url = (*delta)->new_url;
redirected = true;
EventLogEntry log_entry(
@@ -346,6 +372,14 @@ void MergeOnBeforeSendHeadersResponses(
}
}
+// Converts the key of the (key, value) pair to lower case.
+ResponseHeader toLowerCase(const ResponseHeader& header) {
+ std::string lower_key(header.first);
+ std::transform(lower_key.begin(), lower_key.end(),
+ lower_key.begin(), ::tolower);
+ return ResponseHeader(lower_key, header.second);
+}
+
void MergeOnHeadersReceivedResponses(
const EventResponseDeltas& deltas,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
@@ -353,26 +387,61 @@ void MergeOnHeadersReceivedResponses(
EventLogEntries* event_log_entries) {
EventResponseDeltas::const_iterator delta;
- // Whether any extension has overridden the response headers, yet.
- bool headers_overridden = false;
+ // Here we collect which headers we have removed or added so far due to
+ // extensions of higher precedence. Header keys are always stored as
+ // lower case.
+ std::set<ResponseHeader> removed_headers;
+ std::set<ResponseHeader> added_headers;
// We assume here that the deltas are sorted in decreasing extension
// precedence (i.e. decreasing extension installation time).
for (delta = deltas.begin(); delta != deltas.end(); ++delta) {
- if (!(*delta)->new_response_headers.get())
+ if ((*delta)->added_response_headers.empty() &&
+ (*delta)->deleted_response_headers.empty()) {
continue;
+ }
- scoped_refptr<NetLogModificationParameter> log(
- new NetLogModificationParameter((*delta)->extension_id));
-
- // Conflict if a second extension returned new response headers;
- bool extension_conflicts = headers_overridden;
+ // We consider modifications as pairs of (delete, add) operations.
+ // If a header is deleted twice by different extensions we assume that the
+ // intention was to modify it to different values and consider this a
+ // conflict. As deltas is sorted by decreasing extension installation order,
+ // this takes care of precedence.
+ bool extension_conflicts = false;
+ ResponseHeaders::const_iterator i;
+ for (i = (*delta)->deleted_response_headers.begin();
+ i != (*delta)->deleted_response_headers.end(); ++i) {
+ if (removed_headers.find(toLowerCase(*i)) != removed_headers.end()) {
+ extension_conflicts = true;
+ break;
+ }
+ }
+ // Now execute the modifications if there were no conflicts.
if (!extension_conflicts) {
- headers_overridden = true;
- *override_response_headers = (*delta)->new_response_headers;
+ // Delete headers
+ {
+ for (i = (*delta)->deleted_response_headers.begin();
+ i != (*delta)->deleted_response_headers.end(); ++i) {
+ (*override_response_headers)->RemoveHeader(i->first, i->second);
+ removed_headers.insert(toLowerCase(*i));
+ }
+ }
+
+ // Add headers.
+ {
+ for (i = (*delta)->added_response_headers.begin();
+ i != (*delta)->added_response_headers.end(); ++i) {
+ ResponseHeader lowercase_header(toLowerCase(*i));
+ if (added_headers.find(lowercase_header) != added_headers.end())
+ continue;
+ added_headers.insert(lowercase_header);
+ (*override_response_headers)->AddHeader(i->first + ": " + i->second);
+ }
+ }
EventLogEntry log_entry(
- net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, log);
+ net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS,
+ make_scoped_refptr(
+ new NetLogModificationParameter((*delta)->extension_id)));
event_log_entries->push_back(log_entry);
} else {
conflicting_extensions->insert((*delta)->extension_id);
@@ -398,7 +467,11 @@ bool MergeOnAuthRequiredResponses(
++delta) {
if (!(*delta)->auth_credentials.get())
continue;
- if (credentials_set) {
+ bool different =
+ auth_credentials->username() !=
+ (*delta)->auth_credentials->username() ||
+ auth_credentials->password() != (*delta)->auth_credentials->password();
+ if (credentials_set && different) {
conflicting_extensions->insert((*delta)->extension_id);
EventLogEntry log_entry(
net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,

Powered by Google App Engine
This is Rietveld 408576698