OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/extension_webrequest_api_helpers.h" | 5 #include "chrome/browser/extensions/extension_webrequest_api_helpers.h" |
6 | 6 |
| 7 #include "base/string_util.h" |
7 #include "base/values.h" | 8 #include "base/values.h" |
8 #include "chrome/browser/extensions/extension_webrequest_api.h" | 9 #include "chrome/browser/extensions/extension_webrequest_api.h" |
9 #include "net/http/http_util.h" | 10 #include "net/http/http_util.h" |
10 | 11 |
11 namespace extension_webrequest_api_helpers { | 12 namespace extension_webrequest_api_helpers { |
12 | 13 |
13 | 14 |
14 EventResponseDelta::EventResponseDelta( | 15 EventResponseDelta::EventResponseDelta( |
15 const std::string& extension_id, const base::Time& extension_install_time) | 16 const std::string& extension_id, const base::Time& extension_install_time) |
16 : extension_id(extension_id), | 17 : extension_id(extension_id), |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 } | 159 } |
159 } | 160 } |
160 } | 161 } |
161 return result; | 162 return result; |
162 } | 163 } |
163 | 164 |
164 EventResponseDelta* CalculateOnHeadersReceivedDelta( | 165 EventResponseDelta* CalculateOnHeadersReceivedDelta( |
165 const std::string& extension_id, | 166 const std::string& extension_id, |
166 const base::Time& extension_install_time, | 167 const base::Time& extension_install_time, |
167 bool cancel, | 168 bool cancel, |
168 const std::string& status_line, | 169 net::HttpResponseHeaders* old_response_headers, |
169 const std::string& response_headers_string) { | 170 ResponseHeaders* new_response_headers) { |
170 EventResponseDelta* result = | 171 EventResponseDelta* result = |
171 new EventResponseDelta(extension_id, extension_install_time); | 172 new EventResponseDelta(extension_id, extension_install_time); |
172 result->cancel = cancel; | 173 result->cancel = cancel; |
173 | 174 |
174 if (!response_headers_string.empty()) { | 175 if (!new_response_headers) |
175 std::string new_headers_string = | 176 return result; |
176 status_line + "\n" + response_headers_string; | |
177 | 177 |
178 result->new_response_headers = | 178 // Find deleted headers (header keys are treated case insensitively). |
179 new net::HttpResponseHeaders( | 179 { |
180 net::HttpUtil::AssembleRawHeaders(new_headers_string.c_str(), | 180 void* iter = NULL; |
181 new_headers_string.length())); | 181 std::string name; |
| 182 std::string value; |
| 183 while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value)) { |
| 184 std::string name_lowercase(name); |
| 185 StringToLowerASCII(&name_lowercase); |
| 186 |
| 187 bool header_found = false; |
| 188 for (ResponseHeaders::const_iterator i = new_response_headers->begin(); |
| 189 i != new_response_headers->end(); ++i) { |
| 190 if (LowerCaseEqualsASCII(i->first, name_lowercase.c_str()) && |
| 191 value == i->second) { |
| 192 header_found = true; |
| 193 break; |
| 194 } |
| 195 } |
| 196 if (!header_found) |
| 197 result->deleted_response_headers.push_back(ResponseHeader(name, value)); |
| 198 } |
182 } | 199 } |
| 200 |
| 201 // Find added headers (header keys are treated case insensitively). |
| 202 { |
| 203 for (ResponseHeaders::const_iterator i = new_response_headers->begin(); |
| 204 i != new_response_headers->end(); ++i) { |
| 205 void* iter = NULL; |
| 206 std::string value; |
| 207 bool header_found = false; |
| 208 while (old_response_headers->EnumerateHeader(&iter, i->first, &value) && |
| 209 !header_found) { |
| 210 header_found = (value == i->second); |
| 211 } |
| 212 if (!header_found) |
| 213 result->added_response_headers.push_back(*i); |
| 214 } |
| 215 } |
| 216 |
183 return result; | 217 return result; |
184 } | 218 } |
185 | 219 |
186 EventResponseDelta* CalculateOnAuthRequiredDelta( | 220 EventResponseDelta* CalculateOnAuthRequiredDelta( |
187 const std::string& extension_id, | 221 const std::string& extension_id, |
188 const base::Time& extension_install_time, | 222 const base::Time& extension_install_time, |
189 bool cancel, | 223 bool cancel, |
190 scoped_ptr<net::AuthCredentials>* auth_credentials) { | 224 scoped_ptr<net::AuthCredentials>* auth_credentials) { |
191 EventResponseDelta* result = | 225 EventResponseDelta* result = |
192 new EventResponseDelta(extension_id, extension_install_time); | 226 new EventResponseDelta(extension_id, extension_install_time); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 conflicting_extensions->insert((*delta)->extension_id); | 373 conflicting_extensions->insert((*delta)->extension_id); |
340 EventLogEntry log_entry( | 374 EventLogEntry log_entry( |
341 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | 375 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, |
342 make_scoped_refptr( | 376 make_scoped_refptr( |
343 new NetLogExtensionIdParameter((*delta)->extension_id))); | 377 new NetLogExtensionIdParameter((*delta)->extension_id))); |
344 event_log_entries->push_back(log_entry); | 378 event_log_entries->push_back(log_entry); |
345 } | 379 } |
346 } | 380 } |
347 } | 381 } |
348 | 382 |
| 383 // Converts the key of the (key, value) pair to lower case. |
| 384 static ResponseHeader ToLowerCase(const ResponseHeader& header) { |
| 385 std::string lower_key(header.first); |
| 386 StringToLowerASCII(&lower_key); |
| 387 return ResponseHeader(lower_key, header.second); |
| 388 } |
| 389 |
349 void MergeOnHeadersReceivedResponses( | 390 void MergeOnHeadersReceivedResponses( |
350 const EventResponseDeltas& deltas, | 391 const EventResponseDeltas& deltas, |
| 392 const net::HttpResponseHeaders* original_response_headers, |
351 scoped_refptr<net::HttpResponseHeaders>* override_response_headers, | 393 scoped_refptr<net::HttpResponseHeaders>* override_response_headers, |
352 std::set<std::string>* conflicting_extensions, | 394 std::set<std::string>* conflicting_extensions, |
353 EventLogEntries* event_log_entries) { | 395 EventLogEntries* event_log_entries) { |
354 EventResponseDeltas::const_iterator delta; | 396 EventResponseDeltas::const_iterator delta; |
355 | 397 |
356 // Whether any extension has overridden the response headers, yet. | 398 // Here we collect which headers we have removed or added so far due to |
357 bool headers_overridden = false; | 399 // extensions of higher precedence. Header keys are always stored as |
| 400 // lower case. |
| 401 std::set<ResponseHeader> removed_headers; |
| 402 std::set<ResponseHeader> added_headers; |
358 | 403 |
359 // We assume here that the deltas are sorted in decreasing extension | 404 // We assume here that the deltas are sorted in decreasing extension |
360 // precedence (i.e. decreasing extension installation time). | 405 // precedence (i.e. decreasing extension installation time). |
361 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | 406 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { |
362 if (!(*delta)->new_response_headers.get()) | 407 if ((*delta)->added_response_headers.empty() && |
| 408 (*delta)->deleted_response_headers.empty()) { |
363 continue; | 409 continue; |
| 410 } |
364 | 411 |
365 scoped_refptr<NetLogModificationParameter> log( | 412 // Only create a copy if we really want to modify the response headers. |
366 new NetLogModificationParameter((*delta)->extension_id)); | 413 if (override_response_headers->get() == NULL) { |
| 414 *override_response_headers = new net::HttpResponseHeaders( |
| 415 original_response_headers->raw_headers()); |
| 416 } |
367 | 417 |
368 // Conflict if a second extension returned new response headers; | 418 // We consider modifications as pairs of (delete, add) operations. |
369 bool extension_conflicts = headers_overridden; | 419 // If a header is deleted twice by different extensions we assume that the |
| 420 // intention was to modify it to different values and consider this a |
| 421 // conflict. As deltas is sorted by decreasing extension installation order, |
| 422 // this takes care of precedence. |
| 423 bool extension_conflicts = false; |
| 424 ResponseHeaders::const_iterator i; |
| 425 for (i = (*delta)->deleted_response_headers.begin(); |
| 426 i != (*delta)->deleted_response_headers.end(); ++i) { |
| 427 if (removed_headers.find(ToLowerCase(*i)) != removed_headers.end()) { |
| 428 extension_conflicts = true; |
| 429 break; |
| 430 } |
| 431 } |
370 | 432 |
| 433 // Now execute the modifications if there were no conflicts. |
371 if (!extension_conflicts) { | 434 if (!extension_conflicts) { |
372 headers_overridden = true; | 435 // Delete headers |
373 *override_response_headers = (*delta)->new_response_headers; | 436 { |
| 437 for (i = (*delta)->deleted_response_headers.begin(); |
| 438 i != (*delta)->deleted_response_headers.end(); ++i) { |
| 439 (*override_response_headers)->RemoveHeaderWithValue(i->first, |
| 440 i->second); |
| 441 removed_headers.insert(ToLowerCase(*i)); |
| 442 } |
| 443 } |
| 444 |
| 445 // Add headers. |
| 446 { |
| 447 for (i = (*delta)->added_response_headers.begin(); |
| 448 i != (*delta)->added_response_headers.end(); ++i) { |
| 449 ResponseHeader lowercase_header(ToLowerCase(*i)); |
| 450 if (added_headers.find(lowercase_header) != added_headers.end()) |
| 451 continue; |
| 452 added_headers.insert(lowercase_header); |
| 453 (*override_response_headers)->AddHeader(i->first + ": " + i->second); |
| 454 } |
| 455 } |
374 EventLogEntry log_entry( | 456 EventLogEntry log_entry( |
375 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, log); | 457 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, |
| 458 make_scoped_refptr( |
| 459 new NetLogModificationParameter((*delta)->extension_id))); |
376 event_log_entries->push_back(log_entry); | 460 event_log_entries->push_back(log_entry); |
377 } else { | 461 } else { |
378 conflicting_extensions->insert((*delta)->extension_id); | 462 conflicting_extensions->insert((*delta)->extension_id); |
379 EventLogEntry log_entry( | 463 EventLogEntry log_entry( |
380 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | 464 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, |
381 make_scoped_refptr( | 465 make_scoped_refptr( |
382 new NetLogExtensionIdParameter((*delta)->extension_id))); | 466 new NetLogExtensionIdParameter((*delta)->extension_id))); |
383 event_log_entries->push_back(log_entry); | 467 event_log_entries->push_back(log_entry); |
384 } | 468 } |
385 } | 469 } |
(...skipping 30 matching lines...) Expand all Loading... |
416 new NetLogExtensionIdParameter((*delta)->extension_id))); | 500 new NetLogExtensionIdParameter((*delta)->extension_id))); |
417 event_log_entries->push_back(log_entry); | 501 event_log_entries->push_back(log_entry); |
418 *auth_credentials = *(*delta)->auth_credentials; | 502 *auth_credentials = *(*delta)->auth_credentials; |
419 credentials_set = true; | 503 credentials_set = true; |
420 } | 504 } |
421 } | 505 } |
422 return credentials_set; | 506 return credentials_set; |
423 } | 507 } |
424 | 508 |
425 } // namespace extension_webrequest_api_helpers | 509 } // namespace extension_webrequest_api_helpers |
OLD | NEW |