Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: chrome/browser/extensions/extension_webrequest_api_helpers.cc

Issue 8519003: More unittests for webRequest API and better conflict resolution (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improve merging of header modifications in webRequest.OnHeadersReceived Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698