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 ResponseHeader toLowerCase(const ResponseHeader& header) { | |
Matt Perry
2011/11/11 22:05:08
ToLowerCase
also make this static, or put it in a
battre
2011/11/17 12:01:04
Done.
| |
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 | |
Matt Perry
2011/11/11 22:05:08
this seems like a strange assumption to me
battre
2011/11/17 12:01:04
Do you have a better proposal?
Say you have a res
Matt Perry
2011/11/17 20:04:09
It still seems possible to me to distinguish betwe
| |
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)->RemoveHeader(i->first, i->second); | |
440 removed_headers.insert(toLowerCase(*i)); | |
441 } | |
442 } | |
443 | |
444 // Add headers. | |
445 { | |
446 for (i = (*delta)->added_response_headers.begin(); | |
447 i != (*delta)->added_response_headers.end(); ++i) { | |
448 ResponseHeader lowercase_header(toLowerCase(*i)); | |
449 if (added_headers.find(lowercase_header) != added_headers.end()) | |
450 continue; | |
451 added_headers.insert(lowercase_header); | |
452 (*override_response_headers)->AddHeader(i->first + ": " + i->second); | |
453 } | |
454 } | |
374 EventLogEntry log_entry( | 455 EventLogEntry log_entry( |
375 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, log); | 456 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, |
457 make_scoped_refptr( | |
458 new NetLogModificationParameter((*delta)->extension_id))); | |
376 event_log_entries->push_back(log_entry); | 459 event_log_entries->push_back(log_entry); |
377 } else { | 460 } else { |
378 conflicting_extensions->insert((*delta)->extension_id); | 461 conflicting_extensions->insert((*delta)->extension_id); |
379 EventLogEntry log_entry( | 462 EventLogEntry log_entry( |
380 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | 463 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, |
381 make_scoped_refptr( | 464 make_scoped_refptr( |
382 new NetLogExtensionIdParameter((*delta)->extension_id))); | 465 new NetLogExtensionIdParameter((*delta)->extension_id))); |
383 event_log_entries->push_back(log_entry); | 466 event_log_entries->push_back(log_entry); |
384 } | 467 } |
385 } | 468 } |
(...skipping 30 matching lines...) Expand all Loading... | |
416 new NetLogExtensionIdParameter((*delta)->extension_id))); | 499 new NetLogExtensionIdParameter((*delta)->extension_id))); |
417 event_log_entries->push_back(log_entry); | 500 event_log_entries->push_back(log_entry); |
418 *auth_credentials = *(*delta)->auth_credentials; | 501 *auth_credentials = *(*delta)->auth_credentials; |
419 credentials_set = true; | 502 credentials_set = true; |
420 } | 503 } |
421 } | 504 } |
422 return credentials_set; | 505 return credentials_set; |
423 } | 506 } |
424 | 507 |
425 } // namespace extension_webrequest_api_helpers | 508 } // namespace extension_webrequest_api_helpers |
OLD | NEW |