| 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,
|
|
|