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 d9357784c53d30957b4ea059ca09b68d2c6a8b14..7b2da1588dc4d33d28daf647492c2fbeff04bf53 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,54 @@ 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; |
+ if (!new_response_headers) |
+ return result; |
- result->new_response_headers = |
- new net::HttpResponseHeaders( |
- net::HttpUtil::AssembleRawHeaders(new_headers_string.c_str(), |
- new_headers_string.length())); |
+ // Find deleted headers (header keys are treated case insensitively). |
+ { |
+ void* iter = NULL; |
+ std::string name; |
+ std::string value; |
+ while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value)) { |
+ std::string name_lowercase(name); |
+ StringToLowerASCII(&name_lowercase); |
+ |
+ bool header_found = false; |
+ for (ResponseHeaders::const_iterator i = new_response_headers->begin(); |
+ i != new_response_headers->end(); ++i) { |
+ if (LowerCaseEqualsASCII(i->first, name_lowercase.c_str()) && |
+ value == i->second) { |
+ header_found = true; |
+ break; |
+ } |
+ } |
+ if (!header_found) |
+ result->deleted_response_headers.push_back(ResponseHeader(name, value)); |
+ } |
} |
+ |
+ // Find added headers (header keys are treated case insensitively). |
+ { |
+ for (ResponseHeaders::const_iterator i = new_response_headers->begin(); |
+ i != new_response_headers->end(); ++i) { |
+ void* iter = NULL; |
+ std::string value; |
+ bool header_found = false; |
+ while (old_response_headers->EnumerateHeader(&iter, i->first, &value) && |
+ !header_found) { |
+ header_found = (value == i->second); |
+ } |
+ if (!header_found) |
+ result->added_response_headers.push_back(*i); |
+ } |
+ } |
+ |
return result; |
} |
@@ -346,33 +380,83 @@ void MergeOnBeforeSendHeadersResponses( |
} |
} |
+// Converts the key of the (key, value) pair to lower case. |
+static ResponseHeader ToLowerCase(const ResponseHeader& header) { |
+ std::string lower_key(header.first); |
+ StringToLowerASCII(&lower_key); |
+ return ResponseHeader(lower_key, header.second); |
+} |
+ |
void MergeOnHeadersReceivedResponses( |
const EventResponseDeltas& deltas, |
+ const net::HttpResponseHeaders* original_response_headers, |
scoped_refptr<net::HttpResponseHeaders>* override_response_headers, |
std::set<std::string>* conflicting_extensions, |
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)); |
+ // Only create a copy if we really want to modify the response headers. |
+ if (override_response_headers->get() == NULL) { |
+ *override_response_headers = new net::HttpResponseHeaders( |
+ original_response_headers->raw_headers()); |
+ } |
- // 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)->RemoveHeaderWithValue(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); |