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 // Find deleted headers. |
175 std::string new_headers_string = | 176 { |
176 status_line + "\n" + response_headers_string; | 177 void* iter = NULL; |
| 178 std::string name; |
| 179 std::string value; |
| 180 while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value)) { |
| 181 ResponseHeader current_header(name, value); |
| 182 if (std::find(new_response_headers->begin(), |
| 183 new_response_headers->end(), |
| 184 current_header) == new_response_headers->end()) { |
| 185 result->deleted_response_headers.push_back(current_header); |
| 186 } |
| 187 } |
| 188 } |
177 | 189 |
178 result->new_response_headers = | 190 // Find added headers. |
179 new net::HttpResponseHeaders( | 191 { |
180 net::HttpUtil::AssembleRawHeaders(new_headers_string.c_str(), | 192 for (ResponseHeaders::const_iterator i = new_response_headers->begin(); |
181 new_headers_string.length())); | 193 i != new_response_headers->end(); ++i) { |
| 194 bool header_found = false; |
| 195 void* iter = NULL; |
| 196 std::string name; |
| 197 std::string value; |
| 198 // We don't use HttpResponseHeaders::HasHeaderValue because it is |
| 199 // case insensitive |
| 200 while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value) && |
| 201 !header_found) { |
| 202 header_found = (name == i->first) && (value == i->second); |
| 203 } |
| 204 if (!header_found) |
| 205 result->added_response_headers.push_back(*i); |
| 206 } |
182 } | 207 } |
| 208 |
183 return result; | 209 return result; |
184 } | 210 } |
185 | 211 |
186 EventResponseDelta* CalculateOnAuthRequiredDelta( | 212 EventResponseDelta* CalculateOnAuthRequiredDelta( |
187 const std::string& extension_id, | 213 const std::string& extension_id, |
188 const base::Time& extension_install_time, | 214 const base::Time& extension_install_time, |
189 bool cancel, | 215 bool cancel, |
190 scoped_ptr<net::AuthCredentials>* auth_credentials) { | 216 scoped_ptr<net::AuthCredentials>* auth_credentials) { |
191 EventResponseDelta* result = | 217 EventResponseDelta* result = |
192 new EventResponseDelta(extension_id, extension_install_time); | 218 new EventResponseDelta(extension_id, extension_install_time); |
(...skipping 23 matching lines...) Expand all Loading... |
216 void MergeOnBeforeRequestResponses( | 242 void MergeOnBeforeRequestResponses( |
217 const EventResponseDeltas& deltas, | 243 const EventResponseDeltas& deltas, |
218 GURL* new_url, | 244 GURL* new_url, |
219 std::set<std::string>* conflicting_extensions, | 245 std::set<std::string>* conflicting_extensions, |
220 EventLogEntries* event_log_entries) { | 246 EventLogEntries* event_log_entries) { |
221 EventResponseDeltas::const_iterator delta; | 247 EventResponseDeltas::const_iterator delta; |
222 | 248 |
223 bool redirected = false; | 249 bool redirected = false; |
224 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | 250 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { |
225 if (!(*delta)->new_url.is_empty()) { | 251 if (!(*delta)->new_url.is_empty()) { |
226 if (!redirected) { | 252 if (!redirected || *new_url == (*delta)->new_url) { |
227 *new_url = (*delta)->new_url; | 253 *new_url = (*delta)->new_url; |
228 redirected = true; | 254 redirected = true; |
229 EventLogEntry log_entry( | 255 EventLogEntry log_entry( |
230 net::NetLog::TYPE_CHROME_EXTENSION_REDIRECTED_REQUEST, | 256 net::NetLog::TYPE_CHROME_EXTENSION_REDIRECTED_REQUEST, |
231 make_scoped_refptr( | 257 make_scoped_refptr( |
232 new NetLogExtensionIdParameter((*delta)->extension_id))); | 258 new NetLogExtensionIdParameter((*delta)->extension_id))); |
233 event_log_entries->push_back(log_entry); | 259 event_log_entries->push_back(log_entry); |
234 } else { | 260 } else { |
235 conflicting_extensions->insert((*delta)->extension_id); | 261 conflicting_extensions->insert((*delta)->extension_id); |
236 EventLogEntry log_entry( | 262 EventLogEntry log_entry( |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 conflicting_extensions->insert((*delta)->extension_id); | 365 conflicting_extensions->insert((*delta)->extension_id); |
340 EventLogEntry log_entry( | 366 EventLogEntry log_entry( |
341 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | 367 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, |
342 make_scoped_refptr( | 368 make_scoped_refptr( |
343 new NetLogExtensionIdParameter((*delta)->extension_id))); | 369 new NetLogExtensionIdParameter((*delta)->extension_id))); |
344 event_log_entries->push_back(log_entry); | 370 event_log_entries->push_back(log_entry); |
345 } | 371 } |
346 } | 372 } |
347 } | 373 } |
348 | 374 |
| 375 // Converts the key of the (key, value) pair to lower case. |
| 376 ResponseHeader toLowerCase(const ResponseHeader& header) { |
| 377 std::string lower_key(header.first); |
| 378 std::transform(lower_key.begin(), lower_key.end(), |
| 379 lower_key.begin(), ::tolower); |
| 380 return ResponseHeader(lower_key, header.second); |
| 381 } |
| 382 |
349 void MergeOnHeadersReceivedResponses( | 383 void MergeOnHeadersReceivedResponses( |
350 const EventResponseDeltas& deltas, | 384 const EventResponseDeltas& deltas, |
351 scoped_refptr<net::HttpResponseHeaders>* override_response_headers, | 385 scoped_refptr<net::HttpResponseHeaders>* override_response_headers, |
352 std::set<std::string>* conflicting_extensions, | 386 std::set<std::string>* conflicting_extensions, |
353 EventLogEntries* event_log_entries) { | 387 EventLogEntries* event_log_entries) { |
354 EventResponseDeltas::const_iterator delta; | 388 EventResponseDeltas::const_iterator delta; |
355 | 389 |
356 // Whether any extension has overridden the response headers, yet. | 390 // Here we collect which headers we have removed or added so far due to |
357 bool headers_overridden = false; | 391 // extensions of higher precedence. Header keys are always stored as |
| 392 // lower case. |
| 393 std::set<ResponseHeader> removed_headers; |
| 394 std::set<ResponseHeader> added_headers; |
358 | 395 |
359 // We assume here that the deltas are sorted in decreasing extension | 396 // We assume here that the deltas are sorted in decreasing extension |
360 // precedence (i.e. decreasing extension installation time). | 397 // precedence (i.e. decreasing extension installation time). |
361 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | 398 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { |
362 if (!(*delta)->new_response_headers.get()) | 399 if ((*delta)->added_response_headers.empty() && |
| 400 (*delta)->deleted_response_headers.empty()) { |
363 continue; | 401 continue; |
| 402 } |
364 | 403 |
365 scoped_refptr<NetLogModificationParameter> log( | 404 // We consider modifications as pairs of (delete, add) operations. |
366 new NetLogModificationParameter((*delta)->extension_id)); | 405 // If a header is deleted twice by different extensions we assume that the |
| 406 // intention was to modify it to different values and consider this a |
| 407 // conflict. As deltas is sorted by decreasing extension installation order, |
| 408 // this takes care of precedence. |
| 409 bool extension_conflicts = false; |
| 410 ResponseHeaders::const_iterator i; |
| 411 for (i = (*delta)->deleted_response_headers.begin(); |
| 412 i != (*delta)->deleted_response_headers.end(); ++i) { |
| 413 if (removed_headers.find(toLowerCase(*i)) != removed_headers.end()) { |
| 414 extension_conflicts = true; |
| 415 break; |
| 416 } |
| 417 } |
367 | 418 |
368 // Conflict if a second extension returned new response headers; | 419 // Now execute the modifications if there were no conflicts. |
369 bool extension_conflicts = headers_overridden; | 420 if (!extension_conflicts) { |
| 421 // Delete headers |
| 422 { |
| 423 for (i = (*delta)->deleted_response_headers.begin(); |
| 424 i != (*delta)->deleted_response_headers.end(); ++i) { |
| 425 (*override_response_headers)->RemoveHeader(i->first, i->second); |
| 426 removed_headers.insert(toLowerCase(*i)); |
| 427 } |
| 428 } |
370 | 429 |
371 if (!extension_conflicts) { | 430 // Add headers. |
372 headers_overridden = true; | 431 { |
373 *override_response_headers = (*delta)->new_response_headers; | 432 for (i = (*delta)->added_response_headers.begin(); |
| 433 i != (*delta)->added_response_headers.end(); ++i) { |
| 434 ResponseHeader lowercase_header(toLowerCase(*i)); |
| 435 if (added_headers.find(lowercase_header) != added_headers.end()) |
| 436 continue; |
| 437 added_headers.insert(lowercase_header); |
| 438 (*override_response_headers)->AddHeader(i->first + ": " + i->second); |
| 439 } |
| 440 } |
374 EventLogEntry log_entry( | 441 EventLogEntry log_entry( |
375 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, log); | 442 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, |
| 443 make_scoped_refptr( |
| 444 new NetLogModificationParameter((*delta)->extension_id))); |
376 event_log_entries->push_back(log_entry); | 445 event_log_entries->push_back(log_entry); |
377 } else { | 446 } else { |
378 conflicting_extensions->insert((*delta)->extension_id); | 447 conflicting_extensions->insert((*delta)->extension_id); |
379 EventLogEntry log_entry( | 448 EventLogEntry log_entry( |
380 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | 449 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, |
381 make_scoped_refptr( | 450 make_scoped_refptr( |
382 new NetLogExtensionIdParameter((*delta)->extension_id))); | 451 new NetLogExtensionIdParameter((*delta)->extension_id))); |
383 event_log_entries->push_back(log_entry); | 452 event_log_entries->push_back(log_entry); |
384 } | 453 } |
385 } | 454 } |
386 } | 455 } |
387 | 456 |
388 bool MergeOnAuthRequiredResponses( | 457 bool MergeOnAuthRequiredResponses( |
389 const EventResponseDeltas& deltas, | 458 const EventResponseDeltas& deltas, |
390 net::AuthCredentials* auth_credentials, | 459 net::AuthCredentials* auth_credentials, |
391 std::set<std::string>* conflicting_extensions, | 460 std::set<std::string>* conflicting_extensions, |
392 EventLogEntries* event_log_entries) { | 461 EventLogEntries* event_log_entries) { |
393 CHECK(auth_credentials); | 462 CHECK(auth_credentials); |
394 bool credentials_set = false; | 463 bool credentials_set = false; |
395 | 464 |
396 for (EventResponseDeltas::const_iterator delta = deltas.begin(); | 465 for (EventResponseDeltas::const_iterator delta = deltas.begin(); |
397 delta != deltas.end(); | 466 delta != deltas.end(); |
398 ++delta) { | 467 ++delta) { |
399 if (!(*delta)->auth_credentials.get()) | 468 if (!(*delta)->auth_credentials.get()) |
400 continue; | 469 continue; |
401 if (credentials_set) { | 470 bool different = |
| 471 auth_credentials->username() != |
| 472 (*delta)->auth_credentials->username() || |
| 473 auth_credentials->password() != (*delta)->auth_credentials->password(); |
| 474 if (credentials_set && different) { |
402 conflicting_extensions->insert((*delta)->extension_id); | 475 conflicting_extensions->insert((*delta)->extension_id); |
403 EventLogEntry log_entry( | 476 EventLogEntry log_entry( |
404 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | 477 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, |
405 make_scoped_refptr( | 478 make_scoped_refptr( |
406 new NetLogExtensionIdParameter((*delta)->extension_id))); | 479 new NetLogExtensionIdParameter((*delta)->extension_id))); |
407 event_log_entries->push_back(log_entry); | 480 event_log_entries->push_back(log_entry); |
408 } else { | 481 } else { |
409 EventLogEntry log_entry( | 482 EventLogEntry log_entry( |
410 net::NetLog::TYPE_CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS, | 483 net::NetLog::TYPE_CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS, |
411 make_scoped_refptr( | 484 make_scoped_refptr( |
412 new NetLogExtensionIdParameter((*delta)->extension_id))); | 485 new NetLogExtensionIdParameter((*delta)->extension_id))); |
413 event_log_entries->push_back(log_entry); | 486 event_log_entries->push_back(log_entry); |
414 *auth_credentials = *(*delta)->auth_credentials; | 487 *auth_credentials = *(*delta)->auth_credentials; |
415 credentials_set = true; | 488 credentials_set = true; |
416 } | 489 } |
417 } | 490 } |
418 return credentials_set; | 491 return credentials_set; |
419 } | 492 } |
420 | 493 |
421 } // namespace extension_webrequest_api_helpers | 494 } // namespace extension_webrequest_api_helpers |
OLD | NEW |