OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" | |
6 | |
7 #include <cmath> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/strings/string_number_conversions.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/strings/stringprintf.h" | |
13 #include "base/time/time.h" | |
14 #include "base/values.h" | |
15 #include "chrome/browser/extensions/api/web_request/web_request_api.h" | |
16 #include "components/web_cache/browser/web_cache_manager.h" | |
17 #include "content/public/browser/browser_thread.h" | |
18 #include "content/public/browser/render_process_host.h" | |
19 #include "extensions/browser/extension_system.h" | |
20 #include "extensions/browser/runtime_data.h" | |
21 #include "extensions/browser/warning_set.h" | |
22 #include "net/base/net_log.h" | |
23 #include "net/cookies/cookie_util.h" | |
24 #include "net/cookies/parsed_cookie.h" | |
25 #include "net/http/http_util.h" | |
26 #include "net/url_request/url_request.h" | |
27 #include "url/url_constants.h" | |
28 | |
29 // TODO(battre): move all static functions into an anonymous namespace at the | |
30 // top of this file. | |
31 | |
32 using base::Time; | |
33 using net::cookie_util::ParsedRequestCookie; | |
34 using net::cookie_util::ParsedRequestCookies; | |
35 | |
36 namespace extension_web_request_api_helpers { | |
37 | |
38 namespace { | |
39 | |
40 typedef std::vector<linked_ptr<net::ParsedCookie> > ParsedResponseCookies; | |
41 | |
42 void ClearCacheOnNavigationOnUI() { | |
43 web_cache::WebCacheManager::GetInstance()->ClearCacheOnNavigation(); | |
44 } | |
45 | |
46 bool ParseCookieLifetime(net::ParsedCookie* cookie, | |
47 int64* seconds_till_expiry) { | |
48 // 'Max-Age' is processed first because according to: | |
49 // http://tools.ietf.org/html/rfc6265#section-5.3 'Max-Age' attribute | |
50 // overrides 'Expires' attribute. | |
51 if (cookie->HasMaxAge() && | |
52 base::StringToInt64(cookie->MaxAge(), seconds_till_expiry)) { | |
53 return true; | |
54 } | |
55 | |
56 Time parsed_expiry_time; | |
57 if (cookie->HasExpires()) | |
58 parsed_expiry_time = net::cookie_util::ParseCookieTime(cookie->Expires()); | |
59 | |
60 if (!parsed_expiry_time.is_null()) { | |
61 *seconds_till_expiry = | |
62 ceil((parsed_expiry_time - Time::Now()).InSecondsF()); | |
63 return *seconds_till_expiry >= 0; | |
64 } | |
65 return false; | |
66 } | |
67 | |
68 bool NullableEquals(const int* a, const int* b) { | |
69 if ((a && !b) || (!a && b)) | |
70 return false; | |
71 return (!a) || (*a == *b); | |
72 } | |
73 | |
74 bool NullableEquals(const bool* a, const bool* b) { | |
75 if ((a && !b) || (!a && b)) | |
76 return false; | |
77 return (!a) || (*a == *b); | |
78 } | |
79 | |
80 bool NullableEquals(const std::string* a, const std::string* b) { | |
81 if ((a && !b) || (!a && b)) | |
82 return false; | |
83 return (!a) || (*a == *b); | |
84 } | |
85 | |
86 } // namespace | |
87 | |
88 RequestCookie::RequestCookie() {} | |
89 RequestCookie::~RequestCookie() {} | |
90 | |
91 bool NullableEquals(const RequestCookie* a, const RequestCookie* b) { | |
92 if ((a && !b) || (!a && b)) | |
93 return false; | |
94 if (!a) | |
95 return true; | |
96 return NullableEquals(a->name.get(), b->name.get()) && | |
97 NullableEquals(a->value.get(), b->value.get()); | |
98 } | |
99 | |
100 ResponseCookie::ResponseCookie() {} | |
101 ResponseCookie::~ResponseCookie() {} | |
102 | |
103 bool NullableEquals(const ResponseCookie* a, const ResponseCookie* b) { | |
104 if ((a && !b) || (!a && b)) | |
105 return false; | |
106 if (!a) | |
107 return true; | |
108 return NullableEquals(a->name.get(), b->name.get()) && | |
109 NullableEquals(a->value.get(), b->value.get()) && | |
110 NullableEquals(a->expires.get(), b->expires.get()) && | |
111 NullableEquals(a->max_age.get(), b->max_age.get()) && | |
112 NullableEquals(a->domain.get(), b->domain.get()) && | |
113 NullableEquals(a->path.get(), b->path.get()) && | |
114 NullableEquals(a->secure.get(), b->secure.get()) && | |
115 NullableEquals(a->http_only.get(), b->http_only.get()); | |
116 } | |
117 | |
118 FilterResponseCookie::FilterResponseCookie() {} | |
119 FilterResponseCookie::~FilterResponseCookie() {} | |
120 | |
121 bool NullableEquals(const FilterResponseCookie* a, | |
122 const FilterResponseCookie* b) { | |
123 if ((a && !b) || (!a && b)) | |
124 return false; | |
125 if (!a) | |
126 return true; | |
127 return NullableEquals(a->age_lower_bound.get(), b->age_lower_bound.get()) && | |
128 NullableEquals(a->age_upper_bound.get(), b->age_upper_bound.get()) && | |
129 NullableEquals(a->session_cookie.get(), b->session_cookie.get()); | |
130 } | |
131 | |
132 RequestCookieModification::RequestCookieModification() {} | |
133 RequestCookieModification::~RequestCookieModification() {} | |
134 | |
135 bool NullableEquals(const RequestCookieModification* a, | |
136 const RequestCookieModification* b) { | |
137 if ((a && !b) || (!a && b)) | |
138 return false; | |
139 if (!a) | |
140 return true; | |
141 return NullableEquals(a->filter.get(), b->filter.get()) && | |
142 NullableEquals(a->modification.get(), b->modification.get()); | |
143 } | |
144 | |
145 ResponseCookieModification::ResponseCookieModification() : type(ADD) {} | |
146 ResponseCookieModification::~ResponseCookieModification() {} | |
147 | |
148 bool NullableEquals(const ResponseCookieModification* a, | |
149 const ResponseCookieModification* b) { | |
150 if ((a && !b) || (!a && b)) | |
151 return false; | |
152 if (!a) | |
153 return true; | |
154 return a->type == b->type && | |
155 NullableEquals(a->filter.get(), b->filter.get()) && | |
156 NullableEquals(a->modification.get(), b->modification.get()); | |
157 } | |
158 | |
159 EventResponseDelta::EventResponseDelta( | |
160 const std::string& extension_id, const base::Time& extension_install_time) | |
161 : extension_id(extension_id), | |
162 extension_install_time(extension_install_time), | |
163 cancel(false) { | |
164 } | |
165 | |
166 EventResponseDelta::~EventResponseDelta() { | |
167 } | |
168 | |
169 | |
170 // Creates a NetLog callback the returns a Value with the ID of the extension | |
171 // that caused an event. |delta| must remain valid for the lifetime of the | |
172 // callback. | |
173 net::NetLog::ParametersCallback CreateNetLogExtensionIdCallback( | |
174 const EventResponseDelta* delta) { | |
175 return net::NetLog::StringCallback("extension_id", &delta->extension_id); | |
176 } | |
177 | |
178 // Creates NetLog parameters to indicate that an extension modified a request. | |
179 // Caller takes ownership of returned value. | |
180 base::Value* NetLogModificationCallback( | |
181 const EventResponseDelta* delta, | |
182 net::NetLog::LogLevel log_level) { | |
183 base::DictionaryValue* dict = new base::DictionaryValue(); | |
184 dict->SetString("extension_id", delta->extension_id); | |
185 | |
186 base::ListValue* modified_headers = new base::ListValue(); | |
187 net::HttpRequestHeaders::Iterator modification( | |
188 delta->modified_request_headers); | |
189 while (modification.GetNext()) { | |
190 std::string line = modification.name() + ": " + modification.value(); | |
191 modified_headers->Append(new base::StringValue(line)); | |
192 } | |
193 dict->Set("modified_headers", modified_headers); | |
194 | |
195 base::ListValue* deleted_headers = new base::ListValue(); | |
196 for (std::vector<std::string>::const_iterator key = | |
197 delta->deleted_request_headers.begin(); | |
198 key != delta->deleted_request_headers.end(); | |
199 ++key) { | |
200 deleted_headers->Append(new base::StringValue(*key)); | |
201 } | |
202 dict->Set("deleted_headers", deleted_headers); | |
203 return dict; | |
204 } | |
205 | |
206 bool InDecreasingExtensionInstallationTimeOrder( | |
207 const linked_ptr<EventResponseDelta>& a, | |
208 const linked_ptr<EventResponseDelta>& b) { | |
209 return a->extension_install_time > b->extension_install_time; | |
210 } | |
211 | |
212 base::ListValue* StringToCharList(const std::string& s) { | |
213 base::ListValue* result = new base::ListValue; | |
214 for (size_t i = 0, n = s.size(); i < n; ++i) { | |
215 result->Append( | |
216 new base::FundamentalValue( | |
217 *reinterpret_cast<const unsigned char*>(&s[i]))); | |
218 } | |
219 return result; | |
220 } | |
221 | |
222 bool CharListToString(const base::ListValue* list, std::string* out) { | |
223 if (!list) | |
224 return false; | |
225 const size_t list_length = list->GetSize(); | |
226 out->resize(list_length); | |
227 int value = 0; | |
228 for (size_t i = 0; i < list_length; ++i) { | |
229 if (!list->GetInteger(i, &value) || value < 0 || value > 255) | |
230 return false; | |
231 unsigned char tmp = static_cast<unsigned char>(value); | |
232 (*out)[i] = *reinterpret_cast<char*>(&tmp); | |
233 } | |
234 return true; | |
235 } | |
236 | |
237 EventResponseDelta* CalculateOnBeforeRequestDelta( | |
238 const std::string& extension_id, | |
239 const base::Time& extension_install_time, | |
240 bool cancel, | |
241 const GURL& new_url) { | |
242 EventResponseDelta* result = | |
243 new EventResponseDelta(extension_id, extension_install_time); | |
244 result->cancel = cancel; | |
245 result->new_url = new_url; | |
246 return result; | |
247 } | |
248 | |
249 EventResponseDelta* CalculateOnBeforeSendHeadersDelta( | |
250 const std::string& extension_id, | |
251 const base::Time& extension_install_time, | |
252 bool cancel, | |
253 net::HttpRequestHeaders* old_headers, | |
254 net::HttpRequestHeaders* new_headers) { | |
255 EventResponseDelta* result = | |
256 new EventResponseDelta(extension_id, extension_install_time); | |
257 result->cancel = cancel; | |
258 | |
259 // The event listener might not have passed any new headers if he | |
260 // just wanted to cancel the request. | |
261 if (new_headers) { | |
262 // Find deleted headers. | |
263 { | |
264 net::HttpRequestHeaders::Iterator i(*old_headers); | |
265 while (i.GetNext()) { | |
266 if (!new_headers->HasHeader(i.name())) { | |
267 result->deleted_request_headers.push_back(i.name()); | |
268 } | |
269 } | |
270 } | |
271 | |
272 // Find modified headers. | |
273 { | |
274 net::HttpRequestHeaders::Iterator i(*new_headers); | |
275 while (i.GetNext()) { | |
276 std::string value; | |
277 if (!old_headers->GetHeader(i.name(), &value) || i.value() != value) { | |
278 result->modified_request_headers.SetHeader(i.name(), i.value()); | |
279 } | |
280 } | |
281 } | |
282 } | |
283 return result; | |
284 } | |
285 | |
286 EventResponseDelta* CalculateOnHeadersReceivedDelta( | |
287 const std::string& extension_id, | |
288 const base::Time& extension_install_time, | |
289 bool cancel, | |
290 const GURL& new_url, | |
291 const net::HttpResponseHeaders* old_response_headers, | |
292 ResponseHeaders* new_response_headers) { | |
293 EventResponseDelta* result = | |
294 new EventResponseDelta(extension_id, extension_install_time); | |
295 result->cancel = cancel; | |
296 result->new_url = new_url; | |
297 | |
298 if (!new_response_headers) | |
299 return result; | |
300 | |
301 // Find deleted headers (header keys are treated case insensitively). | |
302 { | |
303 void* iter = NULL; | |
304 std::string name; | |
305 std::string value; | |
306 while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
307 std::string name_lowercase(name); | |
308 base::StringToLowerASCII(&name_lowercase); | |
309 | |
310 bool header_found = false; | |
311 for (ResponseHeaders::const_iterator i = new_response_headers->begin(); | |
312 i != new_response_headers->end(); ++i) { | |
313 if (LowerCaseEqualsASCII(i->first, name_lowercase.c_str()) && | |
314 value == i->second) { | |
315 header_found = true; | |
316 break; | |
317 } | |
318 } | |
319 if (!header_found) | |
320 result->deleted_response_headers.push_back(ResponseHeader(name, value)); | |
321 } | |
322 } | |
323 | |
324 // Find added headers (header keys are treated case insensitively). | |
325 { | |
326 for (ResponseHeaders::const_iterator i = new_response_headers->begin(); | |
327 i != new_response_headers->end(); ++i) { | |
328 void* iter = NULL; | |
329 std::string value; | |
330 bool header_found = false; | |
331 while (old_response_headers->EnumerateHeader(&iter, i->first, &value) && | |
332 !header_found) { | |
333 header_found = (value == i->second); | |
334 } | |
335 if (!header_found) | |
336 result->added_response_headers.push_back(*i); | |
337 } | |
338 } | |
339 | |
340 return result; | |
341 } | |
342 | |
343 EventResponseDelta* CalculateOnAuthRequiredDelta( | |
344 const std::string& extension_id, | |
345 const base::Time& extension_install_time, | |
346 bool cancel, | |
347 scoped_ptr<net::AuthCredentials>* auth_credentials) { | |
348 EventResponseDelta* result = | |
349 new EventResponseDelta(extension_id, extension_install_time); | |
350 result->cancel = cancel; | |
351 result->auth_credentials.swap(*auth_credentials); | |
352 return result; | |
353 } | |
354 | |
355 void MergeCancelOfResponses( | |
356 const EventResponseDeltas& deltas, | |
357 bool* canceled, | |
358 const net::BoundNetLog* net_log) { | |
359 for (EventResponseDeltas::const_iterator i = deltas.begin(); | |
360 i != deltas.end(); ++i) { | |
361 if ((*i)->cancel) { | |
362 *canceled = true; | |
363 net_log->AddEvent( | |
364 net::NetLog::TYPE_CHROME_EXTENSION_ABORTED_REQUEST, | |
365 CreateNetLogExtensionIdCallback(i->get())); | |
366 break; | |
367 } | |
368 } | |
369 } | |
370 | |
371 // Helper function for MergeRedirectUrlOfResponses() that allows ignoring | |
372 // all redirects but those to data:// urls and about:blank. This is important | |
373 // to treat these URLs as "cancel urls", i.e. URLs that extensions redirect | |
374 // to if they want to express that they want to cancel a request. This reduces | |
375 // the number of conflicts that we need to flag, as canceling is considered | |
376 // a higher precedence operation that redirects. | |
377 // Returns whether a redirect occurred. | |
378 static bool MergeRedirectUrlOfResponsesHelper( | |
379 const EventResponseDeltas& deltas, | |
380 GURL* new_url, | |
381 extensions::WarningSet* conflicting_extensions, | |
382 const net::BoundNetLog* net_log, | |
383 bool consider_only_cancel_scheme_urls) { | |
384 bool redirected = false; | |
385 | |
386 // Extension that determines the |new_url|. | |
387 std::string winning_extension_id; | |
388 EventResponseDeltas::const_iterator delta; | |
389 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
390 if ((*delta)->new_url.is_empty()) | |
391 continue; | |
392 if (consider_only_cancel_scheme_urls && | |
393 !(*delta)->new_url.SchemeIs(url::kDataScheme) && | |
394 (*delta)->new_url.spec() != "about:blank") { | |
395 continue; | |
396 } | |
397 | |
398 if (!redirected || *new_url == (*delta)->new_url) { | |
399 *new_url = (*delta)->new_url; | |
400 winning_extension_id = (*delta)->extension_id; | |
401 redirected = true; | |
402 net_log->AddEvent( | |
403 net::NetLog::TYPE_CHROME_EXTENSION_REDIRECTED_REQUEST, | |
404 CreateNetLogExtensionIdCallback(delta->get())); | |
405 } else { | |
406 conflicting_extensions->insert( | |
407 extensions::Warning::CreateRedirectConflictWarning( | |
408 (*delta)->extension_id, | |
409 winning_extension_id, | |
410 (*delta)->new_url, | |
411 *new_url)); | |
412 net_log->AddEvent( | |
413 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | |
414 CreateNetLogExtensionIdCallback(delta->get())); | |
415 } | |
416 } | |
417 return redirected; | |
418 } | |
419 | |
420 void MergeRedirectUrlOfResponses( | |
421 const EventResponseDeltas& deltas, | |
422 GURL* new_url, | |
423 extensions::WarningSet* conflicting_extensions, | |
424 const net::BoundNetLog* net_log) { | |
425 | |
426 // First handle only redirects to data:// URLs and about:blank. These are a | |
427 // special case as they represent a way of cancelling a request. | |
428 if (MergeRedirectUrlOfResponsesHelper( | |
429 deltas, new_url, conflicting_extensions, net_log, true)) { | |
430 // If any extension cancelled a request by redirecting to a data:// URL or | |
431 // about:blank, we don't consider the other redirects. | |
432 return; | |
433 } | |
434 | |
435 // Handle all other redirects. | |
436 MergeRedirectUrlOfResponsesHelper( | |
437 deltas, new_url, conflicting_extensions, net_log, false); | |
438 } | |
439 | |
440 void MergeOnBeforeRequestResponses( | |
441 const EventResponseDeltas& deltas, | |
442 GURL* new_url, | |
443 extensions::WarningSet* conflicting_extensions, | |
444 const net::BoundNetLog* net_log) { | |
445 MergeRedirectUrlOfResponses(deltas, new_url, conflicting_extensions, net_log); | |
446 } | |
447 | |
448 static bool DoesRequestCookieMatchFilter( | |
449 const ParsedRequestCookie& cookie, | |
450 RequestCookie* filter) { | |
451 if (!filter) return true; | |
452 if (filter->name.get() && cookie.first != *filter->name) return false; | |
453 if (filter->value.get() && cookie.second != *filter->value) return false; | |
454 return true; | |
455 } | |
456 | |
457 // Applies all CookieModificationType::ADD operations for request cookies of | |
458 // |deltas| to |cookies|. Returns whether any cookie was added. | |
459 static bool MergeAddRequestCookieModifications( | |
460 const EventResponseDeltas& deltas, | |
461 ParsedRequestCookies* cookies) { | |
462 bool modified = false; | |
463 // We assume here that the deltas are sorted in decreasing extension | |
464 // precedence (i.e. decreasing extension installation time). | |
465 EventResponseDeltas::const_reverse_iterator delta; | |
466 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
467 const RequestCookieModifications& modifications = | |
468 (*delta)->request_cookie_modifications; | |
469 for (RequestCookieModifications::const_iterator mod = modifications.begin(); | |
470 mod != modifications.end(); ++mod) { | |
471 if ((*mod)->type != ADD || !(*mod)->modification.get()) | |
472 continue; | |
473 std::string* new_name = (*mod)->modification->name.get(); | |
474 std::string* new_value = (*mod)->modification->value.get(); | |
475 if (!new_name || !new_value) | |
476 continue; | |
477 | |
478 bool cookie_with_same_name_found = false; | |
479 for (ParsedRequestCookies::iterator cookie = cookies->begin(); | |
480 cookie != cookies->end() && !cookie_with_same_name_found; ++cookie) { | |
481 if (cookie->first == *new_name) { | |
482 if (cookie->second != *new_value) { | |
483 cookie->second = *new_value; | |
484 modified = true; | |
485 } | |
486 cookie_with_same_name_found = true; | |
487 } | |
488 } | |
489 if (!cookie_with_same_name_found) { | |
490 cookies->push_back(std::make_pair(base::StringPiece(*new_name), | |
491 base::StringPiece(*new_value))); | |
492 modified = true; | |
493 } | |
494 } | |
495 } | |
496 return modified; | |
497 } | |
498 | |
499 // Applies all CookieModificationType::EDIT operations for request cookies of | |
500 // |deltas| to |cookies|. Returns whether any cookie was modified. | |
501 static bool MergeEditRequestCookieModifications( | |
502 const EventResponseDeltas& deltas, | |
503 ParsedRequestCookies* cookies) { | |
504 bool modified = false; | |
505 // We assume here that the deltas are sorted in decreasing extension | |
506 // precedence (i.e. decreasing extension installation time). | |
507 EventResponseDeltas::const_reverse_iterator delta; | |
508 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
509 const RequestCookieModifications& modifications = | |
510 (*delta)->request_cookie_modifications; | |
511 for (RequestCookieModifications::const_iterator mod = modifications.begin(); | |
512 mod != modifications.end(); ++mod) { | |
513 if ((*mod)->type != EDIT || !(*mod)->modification.get()) | |
514 continue; | |
515 | |
516 std::string* new_value = (*mod)->modification->value.get(); | |
517 RequestCookie* filter = (*mod)->filter.get(); | |
518 for (ParsedRequestCookies::iterator cookie = cookies->begin(); | |
519 cookie != cookies->end(); ++cookie) { | |
520 if (!DoesRequestCookieMatchFilter(*cookie, filter)) | |
521 continue; | |
522 // If the edit operation tries to modify the cookie name, we just ignore | |
523 // this. We only modify the cookie value. | |
524 if (new_value && cookie->second != *new_value) { | |
525 cookie->second = *new_value; | |
526 modified = true; | |
527 } | |
528 } | |
529 } | |
530 } | |
531 return modified; | |
532 } | |
533 | |
534 // Applies all CookieModificationType::REMOVE operations for request cookies of | |
535 // |deltas| to |cookies|. Returns whether any cookie was deleted. | |
536 static bool MergeRemoveRequestCookieModifications( | |
537 const EventResponseDeltas& deltas, | |
538 ParsedRequestCookies* cookies) { | |
539 bool modified = false; | |
540 // We assume here that the deltas are sorted in decreasing extension | |
541 // precedence (i.e. decreasing extension installation time). | |
542 EventResponseDeltas::const_reverse_iterator delta; | |
543 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
544 const RequestCookieModifications& modifications = | |
545 (*delta)->request_cookie_modifications; | |
546 for (RequestCookieModifications::const_iterator mod = modifications.begin(); | |
547 mod != modifications.end(); ++mod) { | |
548 if ((*mod)->type != REMOVE) | |
549 continue; | |
550 | |
551 RequestCookie* filter = (*mod)->filter.get(); | |
552 ParsedRequestCookies::iterator i = cookies->begin(); | |
553 while (i != cookies->end()) { | |
554 if (DoesRequestCookieMatchFilter(*i, filter)) { | |
555 i = cookies->erase(i); | |
556 modified = true; | |
557 } else { | |
558 ++i; | |
559 } | |
560 } | |
561 } | |
562 } | |
563 return modified; | |
564 } | |
565 | |
566 void MergeCookiesInOnBeforeSendHeadersResponses( | |
567 const EventResponseDeltas& deltas, | |
568 net::HttpRequestHeaders* request_headers, | |
569 extensions::WarningSet* conflicting_extensions, | |
570 const net::BoundNetLog* net_log) { | |
571 // Skip all work if there are no registered cookie modifications. | |
572 bool cookie_modifications_exist = false; | |
573 EventResponseDeltas::const_iterator delta; | |
574 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
575 cookie_modifications_exist |= | |
576 !(*delta)->request_cookie_modifications.empty(); | |
577 } | |
578 if (!cookie_modifications_exist) | |
579 return; | |
580 | |
581 // Parse old cookie line. | |
582 std::string cookie_header; | |
583 request_headers->GetHeader(net::HttpRequestHeaders::kCookie, &cookie_header); | |
584 ParsedRequestCookies cookies; | |
585 net::cookie_util::ParseRequestCookieLine(cookie_header, &cookies); | |
586 | |
587 // Modify cookies. | |
588 bool modified = false; | |
589 modified |= MergeAddRequestCookieModifications(deltas, &cookies); | |
590 modified |= MergeEditRequestCookieModifications(deltas, &cookies); | |
591 modified |= MergeRemoveRequestCookieModifications(deltas, &cookies); | |
592 | |
593 // Reassemble and store new cookie line. | |
594 if (modified) { | |
595 std::string new_cookie_header = | |
596 net::cookie_util::SerializeRequestCookieLine(cookies); | |
597 request_headers->SetHeader(net::HttpRequestHeaders::kCookie, | |
598 new_cookie_header); | |
599 } | |
600 } | |
601 | |
602 // Returns the extension ID of the first extension in |deltas| that sets the | |
603 // request header identified by |key| to |value|. | |
604 static std::string FindSetRequestHeader( | |
605 const EventResponseDeltas& deltas, | |
606 const std::string& key, | |
607 const std::string& value) { | |
608 EventResponseDeltas::const_iterator delta; | |
609 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
610 net::HttpRequestHeaders::Iterator modification( | |
611 (*delta)->modified_request_headers); | |
612 while (modification.GetNext()) { | |
613 if (key == modification.name() && value == modification.value()) | |
614 return (*delta)->extension_id; | |
615 } | |
616 } | |
617 return std::string(); | |
618 } | |
619 | |
620 // Returns the extension ID of the first extension in |deltas| that removes the | |
621 // request header identified by |key|. | |
622 static std::string FindRemoveRequestHeader( | |
623 const EventResponseDeltas& deltas, | |
624 const std::string& key) { | |
625 EventResponseDeltas::const_iterator delta; | |
626 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
627 std::vector<std::string>::iterator i; | |
628 for (i = (*delta)->deleted_request_headers.begin(); | |
629 i != (*delta)->deleted_request_headers.end(); | |
630 ++i) { | |
631 if (*i == key) | |
632 return (*delta)->extension_id; | |
633 } | |
634 } | |
635 return std::string(); | |
636 } | |
637 | |
638 void MergeOnBeforeSendHeadersResponses( | |
639 const EventResponseDeltas& deltas, | |
640 net::HttpRequestHeaders* request_headers, | |
641 extensions::WarningSet* conflicting_extensions, | |
642 const net::BoundNetLog* net_log) { | |
643 EventResponseDeltas::const_iterator delta; | |
644 | |
645 // Here we collect which headers we have removed or set to new values | |
646 // so far due to extensions of higher precedence. | |
647 std::set<std::string> removed_headers; | |
648 std::set<std::string> set_headers; | |
649 | |
650 // We assume here that the deltas are sorted in decreasing extension | |
651 // precedence (i.e. decreasing extension installation time). | |
652 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
653 if ((*delta)->modified_request_headers.IsEmpty() && | |
654 (*delta)->deleted_request_headers.empty()) { | |
655 continue; | |
656 } | |
657 | |
658 // Check whether any modification affects a request header that | |
659 // has been modified differently before. As deltas is sorted by decreasing | |
660 // extension installation order, this takes care of precedence. | |
661 bool extension_conflicts = false; | |
662 std::string winning_extension_id; | |
663 std::string conflicting_header; | |
664 { | |
665 net::HttpRequestHeaders::Iterator modification( | |
666 (*delta)->modified_request_headers); | |
667 while (modification.GetNext() && !extension_conflicts) { | |
668 // This modification sets |key| to |value|. | |
669 const std::string& key = modification.name(); | |
670 const std::string& value = modification.value(); | |
671 | |
672 // We must not delete anything that has been modified before. | |
673 if (removed_headers.find(key) != removed_headers.end() && | |
674 !extension_conflicts) { | |
675 winning_extension_id = FindRemoveRequestHeader(deltas, key); | |
676 conflicting_header = key; | |
677 extension_conflicts = true; | |
678 } | |
679 | |
680 // We must not modify anything that has been set to a *different* | |
681 // value before. | |
682 if (set_headers.find(key) != set_headers.end() && | |
683 !extension_conflicts) { | |
684 std::string current_value; | |
685 if (!request_headers->GetHeader(key, ¤t_value) || | |
686 current_value != value) { | |
687 winning_extension_id = | |
688 FindSetRequestHeader(deltas, key, current_value); | |
689 conflicting_header = key; | |
690 extension_conflicts = true; | |
691 } | |
692 } | |
693 } | |
694 } | |
695 | |
696 // Check whether any deletion affects a request header that has been | |
697 // modified before. | |
698 { | |
699 std::vector<std::string>::iterator key; | |
700 for (key = (*delta)->deleted_request_headers.begin(); | |
701 key != (*delta)->deleted_request_headers.end() && | |
702 !extension_conflicts; | |
703 ++key) { | |
704 if (set_headers.find(*key) != set_headers.end()) { | |
705 std::string current_value; | |
706 request_headers->GetHeader(*key, ¤t_value); | |
707 winning_extension_id = | |
708 FindSetRequestHeader(deltas, *key, current_value); | |
709 conflicting_header = *key; | |
710 extension_conflicts = true; | |
711 } | |
712 } | |
713 } | |
714 | |
715 // Now execute the modifications if there were no conflicts. | |
716 if (!extension_conflicts) { | |
717 // Copy all modifications into the original headers. | |
718 request_headers->MergeFrom((*delta)->modified_request_headers); | |
719 { | |
720 // Record which keys were changed. | |
721 net::HttpRequestHeaders::Iterator modification( | |
722 (*delta)->modified_request_headers); | |
723 while (modification.GetNext()) | |
724 set_headers.insert(modification.name()); | |
725 } | |
726 | |
727 // Perform all deletions and record which keys were deleted. | |
728 { | |
729 std::vector<std::string>::iterator key; | |
730 for (key = (*delta)->deleted_request_headers.begin(); | |
731 key != (*delta)->deleted_request_headers.end(); | |
732 ++key) { | |
733 request_headers->RemoveHeader(*key); | |
734 removed_headers.insert(*key); | |
735 } | |
736 } | |
737 net_log->AddEvent( | |
738 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, | |
739 base::Bind(&NetLogModificationCallback, delta->get())); | |
740 } else { | |
741 conflicting_extensions->insert( | |
742 extensions::Warning::CreateRequestHeaderConflictWarning( | |
743 (*delta)->extension_id, winning_extension_id, | |
744 conflicting_header)); | |
745 net_log->AddEvent( | |
746 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | |
747 CreateNetLogExtensionIdCallback(delta->get())); | |
748 } | |
749 } | |
750 | |
751 MergeCookiesInOnBeforeSendHeadersResponses(deltas, request_headers, | |
752 conflicting_extensions, net_log); | |
753 } | |
754 | |
755 // Retrives all cookies from |override_response_headers|. | |
756 static ParsedResponseCookies GetResponseCookies( | |
757 scoped_refptr<net::HttpResponseHeaders> override_response_headers) { | |
758 ParsedResponseCookies result; | |
759 | |
760 void* iter = NULL; | |
761 std::string value; | |
762 while (override_response_headers->EnumerateHeader(&iter, "Set-Cookie", | |
763 &value)) { | |
764 result.push_back(make_linked_ptr(new net::ParsedCookie(value))); | |
765 } | |
766 return result; | |
767 } | |
768 | |
769 // Stores all |cookies| in |override_response_headers| deleting previously | |
770 // existing cookie definitions. | |
771 static void StoreResponseCookies( | |
772 const ParsedResponseCookies& cookies, | |
773 scoped_refptr<net::HttpResponseHeaders> override_response_headers) { | |
774 override_response_headers->RemoveHeader("Set-Cookie"); | |
775 for (ParsedResponseCookies::const_iterator i = cookies.begin(); | |
776 i != cookies.end(); ++i) { | |
777 override_response_headers->AddHeader("Set-Cookie: " + (*i)->ToCookieLine()); | |
778 } | |
779 } | |
780 | |
781 // Modifies |cookie| according to |modification|. Each value that is set in | |
782 // |modification| is applied to |cookie|. | |
783 static bool ApplyResponseCookieModification(ResponseCookie* modification, | |
784 net::ParsedCookie* cookie) { | |
785 bool modified = false; | |
786 if (modification->name.get()) | |
787 modified |= cookie->SetName(*modification->name); | |
788 if (modification->value.get()) | |
789 modified |= cookie->SetValue(*modification->value); | |
790 if (modification->expires.get()) | |
791 modified |= cookie->SetExpires(*modification->expires); | |
792 if (modification->max_age.get()) | |
793 modified |= cookie->SetMaxAge(base::IntToString(*modification->max_age)); | |
794 if (modification->domain.get()) | |
795 modified |= cookie->SetDomain(*modification->domain); | |
796 if (modification->path.get()) | |
797 modified |= cookie->SetPath(*modification->path); | |
798 if (modification->secure.get()) | |
799 modified |= cookie->SetIsSecure(*modification->secure); | |
800 if (modification->http_only.get()) | |
801 modified |= cookie->SetIsHttpOnly(*modification->http_only); | |
802 return modified; | |
803 } | |
804 | |
805 static bool DoesResponseCookieMatchFilter(net::ParsedCookie* cookie, | |
806 FilterResponseCookie* filter) { | |
807 if (!cookie->IsValid()) return false; | |
808 if (!filter) return true; | |
809 if (filter->name && cookie->Name() != *filter->name) | |
810 return false; | |
811 if (filter->value && cookie->Value() != *filter->value) | |
812 return false; | |
813 if (filter->expires) { | |
814 std::string actual_value = | |
815 cookie->HasExpires() ? cookie->Expires() : std::string(); | |
816 if (actual_value != *filter->expires) | |
817 return false; | |
818 } | |
819 if (filter->max_age) { | |
820 std::string actual_value = | |
821 cookie->HasMaxAge() ? cookie->MaxAge() : std::string(); | |
822 if (actual_value != base::IntToString(*filter->max_age)) | |
823 return false; | |
824 } | |
825 if (filter->domain) { | |
826 std::string actual_value = | |
827 cookie->HasDomain() ? cookie->Domain() : std::string(); | |
828 if (actual_value != *filter->domain) | |
829 return false; | |
830 } | |
831 if (filter->path) { | |
832 std::string actual_value = | |
833 cookie->HasPath() ? cookie->Path() : std::string(); | |
834 if (actual_value != *filter->path) | |
835 return false; | |
836 } | |
837 if (filter->secure && cookie->IsSecure() != *filter->secure) | |
838 return false; | |
839 if (filter->http_only && cookie->IsHttpOnly() != *filter->http_only) | |
840 return false; | |
841 if (filter->age_upper_bound || filter->age_lower_bound || | |
842 (filter->session_cookie && *filter->session_cookie)) { | |
843 int64 seconds_to_expiry; | |
844 bool lifetime_parsed = ParseCookieLifetime(cookie, &seconds_to_expiry); | |
845 if (filter->age_upper_bound && seconds_to_expiry > *filter->age_upper_bound) | |
846 return false; | |
847 if (filter->age_lower_bound && seconds_to_expiry < *filter->age_lower_bound) | |
848 return false; | |
849 if (filter->session_cookie && *filter->session_cookie && lifetime_parsed) | |
850 return false; | |
851 } | |
852 return true; | |
853 } | |
854 | |
855 // Applies all CookieModificationType::ADD operations for response cookies of | |
856 // |deltas| to |cookies|. Returns whether any cookie was added. | |
857 static bool MergeAddResponseCookieModifications( | |
858 const EventResponseDeltas& deltas, | |
859 ParsedResponseCookies* cookies) { | |
860 bool modified = false; | |
861 // We assume here that the deltas are sorted in decreasing extension | |
862 // precedence (i.e. decreasing extension installation time). | |
863 EventResponseDeltas::const_reverse_iterator delta; | |
864 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
865 const ResponseCookieModifications& modifications = | |
866 (*delta)->response_cookie_modifications; | |
867 for (ResponseCookieModifications::const_iterator mod = | |
868 modifications.begin(); mod != modifications.end(); ++mod) { | |
869 if ((*mod)->type != ADD || !(*mod)->modification.get()) | |
870 continue; | |
871 // Cookie names are not unique in response cookies so we always append | |
872 // and never override. | |
873 linked_ptr<net::ParsedCookie> cookie( | |
874 new net::ParsedCookie(std::string())); | |
875 ApplyResponseCookieModification((*mod)->modification.get(), cookie.get()); | |
876 cookies->push_back(cookie); | |
877 modified = true; | |
878 } | |
879 } | |
880 return modified; | |
881 } | |
882 | |
883 // Applies all CookieModificationType::EDIT operations for response cookies of | |
884 // |deltas| to |cookies|. Returns whether any cookie was modified. | |
885 static bool MergeEditResponseCookieModifications( | |
886 const EventResponseDeltas& deltas, | |
887 ParsedResponseCookies* cookies) { | |
888 bool modified = false; | |
889 // We assume here that the deltas are sorted in decreasing extension | |
890 // precedence (i.e. decreasing extension installation time). | |
891 EventResponseDeltas::const_reverse_iterator delta; | |
892 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
893 const ResponseCookieModifications& modifications = | |
894 (*delta)->response_cookie_modifications; | |
895 for (ResponseCookieModifications::const_iterator mod = | |
896 modifications.begin(); mod != modifications.end(); ++mod) { | |
897 if ((*mod)->type != EDIT || !(*mod)->modification.get()) | |
898 continue; | |
899 | |
900 for (ParsedResponseCookies::iterator cookie = cookies->begin(); | |
901 cookie != cookies->end(); ++cookie) { | |
902 if (DoesResponseCookieMatchFilter(cookie->get(), | |
903 (*mod)->filter.get())) { | |
904 modified |= ApplyResponseCookieModification( | |
905 (*mod)->modification.get(), cookie->get()); | |
906 } | |
907 } | |
908 } | |
909 } | |
910 return modified; | |
911 } | |
912 | |
913 // Applies all CookieModificationType::REMOVE operations for response cookies of | |
914 // |deltas| to |cookies|. Returns whether any cookie was deleted. | |
915 static bool MergeRemoveResponseCookieModifications( | |
916 const EventResponseDeltas& deltas, | |
917 ParsedResponseCookies* cookies) { | |
918 bool modified = false; | |
919 // We assume here that the deltas are sorted in decreasing extension | |
920 // precedence (i.e. decreasing extension installation time). | |
921 EventResponseDeltas::const_reverse_iterator delta; | |
922 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
923 const ResponseCookieModifications& modifications = | |
924 (*delta)->response_cookie_modifications; | |
925 for (ResponseCookieModifications::const_iterator mod = | |
926 modifications.begin(); mod != modifications.end(); ++mod) { | |
927 if ((*mod)->type != REMOVE) | |
928 continue; | |
929 | |
930 ParsedResponseCookies::iterator i = cookies->begin(); | |
931 while (i != cookies->end()) { | |
932 if (DoesResponseCookieMatchFilter(i->get(), | |
933 (*mod)->filter.get())) { | |
934 i = cookies->erase(i); | |
935 modified = true; | |
936 } else { | |
937 ++i; | |
938 } | |
939 } | |
940 } | |
941 } | |
942 return modified; | |
943 } | |
944 | |
945 void MergeCookiesInOnHeadersReceivedResponses( | |
946 const EventResponseDeltas& deltas, | |
947 const net::HttpResponseHeaders* original_response_headers, | |
948 scoped_refptr<net::HttpResponseHeaders>* override_response_headers, | |
949 extensions::WarningSet* conflicting_extensions, | |
950 const net::BoundNetLog* net_log) { | |
951 // Skip all work if there are no registered cookie modifications. | |
952 bool cookie_modifications_exist = false; | |
953 EventResponseDeltas::const_reverse_iterator delta; | |
954 for (delta = deltas.rbegin(); delta != deltas.rend(); ++delta) { | |
955 cookie_modifications_exist |= | |
956 !(*delta)->response_cookie_modifications.empty(); | |
957 } | |
958 if (!cookie_modifications_exist) | |
959 return; | |
960 | |
961 // Only create a copy if we really want to modify the response headers. | |
962 if (override_response_headers->get() == NULL) { | |
963 *override_response_headers = new net::HttpResponseHeaders( | |
964 original_response_headers->raw_headers()); | |
965 } | |
966 | |
967 ParsedResponseCookies cookies = | |
968 GetResponseCookies(*override_response_headers); | |
969 | |
970 bool modified = false; | |
971 modified |= MergeAddResponseCookieModifications(deltas, &cookies); | |
972 modified |= MergeEditResponseCookieModifications(deltas, &cookies); | |
973 modified |= MergeRemoveResponseCookieModifications(deltas, &cookies); | |
974 | |
975 // Store new value. | |
976 if (modified) | |
977 StoreResponseCookies(cookies, *override_response_headers); | |
978 } | |
979 | |
980 // Converts the key of the (key, value) pair to lower case. | |
981 static ResponseHeader ToLowerCase(const ResponseHeader& header) { | |
982 std::string lower_key(header.first); | |
983 base::StringToLowerASCII(&lower_key); | |
984 return ResponseHeader(lower_key, header.second); | |
985 } | |
986 | |
987 // Returns the extension ID of the first extension in |deltas| that removes the | |
988 // request header identified by |key|. | |
989 static std::string FindRemoveResponseHeader( | |
990 const EventResponseDeltas& deltas, | |
991 const std::string& key) { | |
992 std::string lower_key = base::StringToLowerASCII(key); | |
993 EventResponseDeltas::const_iterator delta; | |
994 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
995 ResponseHeaders::const_iterator i; | |
996 for (i = (*delta)->deleted_response_headers.begin(); | |
997 i != (*delta)->deleted_response_headers.end(); ++i) { | |
998 if (base::StringToLowerASCII(i->first) == lower_key) | |
999 return (*delta)->extension_id; | |
1000 } | |
1001 } | |
1002 return std::string(); | |
1003 } | |
1004 | |
1005 void MergeOnHeadersReceivedResponses( | |
1006 const EventResponseDeltas& deltas, | |
1007 const net::HttpResponseHeaders* original_response_headers, | |
1008 scoped_refptr<net::HttpResponseHeaders>* override_response_headers, | |
1009 GURL* allowed_unsafe_redirect_url, | |
1010 extensions::WarningSet* conflicting_extensions, | |
1011 const net::BoundNetLog* net_log) { | |
1012 EventResponseDeltas::const_iterator delta; | |
1013 | |
1014 // Here we collect which headers we have removed or added so far due to | |
1015 // extensions of higher precedence. Header keys are always stored as | |
1016 // lower case. | |
1017 std::set<ResponseHeader> removed_headers; | |
1018 std::set<ResponseHeader> added_headers; | |
1019 | |
1020 // We assume here that the deltas are sorted in decreasing extension | |
1021 // precedence (i.e. decreasing extension installation time). | |
1022 for (delta = deltas.begin(); delta != deltas.end(); ++delta) { | |
1023 if ((*delta)->added_response_headers.empty() && | |
1024 (*delta)->deleted_response_headers.empty()) { | |
1025 continue; | |
1026 } | |
1027 | |
1028 // Only create a copy if we really want to modify the response headers. | |
1029 if (override_response_headers->get() == NULL) { | |
1030 *override_response_headers = new net::HttpResponseHeaders( | |
1031 original_response_headers->raw_headers()); | |
1032 } | |
1033 | |
1034 // We consider modifications as pairs of (delete, add) operations. | |
1035 // If a header is deleted twice by different extensions we assume that the | |
1036 // intention was to modify it to different values and consider this a | |
1037 // conflict. As deltas is sorted by decreasing extension installation order, | |
1038 // this takes care of precedence. | |
1039 bool extension_conflicts = false; | |
1040 std::string conflicting_header; | |
1041 std::string winning_extension_id; | |
1042 ResponseHeaders::const_iterator i; | |
1043 for (i = (*delta)->deleted_response_headers.begin(); | |
1044 i != (*delta)->deleted_response_headers.end(); ++i) { | |
1045 if (removed_headers.find(ToLowerCase(*i)) != removed_headers.end()) { | |
1046 winning_extension_id = FindRemoveResponseHeader(deltas, i->first); | |
1047 conflicting_header = i->first; | |
1048 extension_conflicts = true; | |
1049 break; | |
1050 } | |
1051 } | |
1052 | |
1053 // Now execute the modifications if there were no conflicts. | |
1054 if (!extension_conflicts) { | |
1055 // Delete headers | |
1056 { | |
1057 for (i = (*delta)->deleted_response_headers.begin(); | |
1058 i != (*delta)->deleted_response_headers.end(); ++i) { | |
1059 (*override_response_headers)->RemoveHeaderLine(i->first, i->second); | |
1060 removed_headers.insert(ToLowerCase(*i)); | |
1061 } | |
1062 } | |
1063 | |
1064 // Add headers. | |
1065 { | |
1066 for (i = (*delta)->added_response_headers.begin(); | |
1067 i != (*delta)->added_response_headers.end(); ++i) { | |
1068 ResponseHeader lowercase_header(ToLowerCase(*i)); | |
1069 if (added_headers.find(lowercase_header) != added_headers.end()) | |
1070 continue; | |
1071 added_headers.insert(lowercase_header); | |
1072 (*override_response_headers)->AddHeader(i->first + ": " + i->second); | |
1073 } | |
1074 } | |
1075 net_log->AddEvent( | |
1076 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, | |
1077 CreateNetLogExtensionIdCallback(delta->get())); | |
1078 } else { | |
1079 conflicting_extensions->insert( | |
1080 extensions::Warning::CreateResponseHeaderConflictWarning( | |
1081 (*delta)->extension_id, winning_extension_id, | |
1082 conflicting_header)); | |
1083 net_log->AddEvent( | |
1084 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | |
1085 CreateNetLogExtensionIdCallback(delta->get())); | |
1086 } | |
1087 } | |
1088 | |
1089 MergeCookiesInOnHeadersReceivedResponses(deltas, original_response_headers, | |
1090 override_response_headers, conflicting_extensions, net_log); | |
1091 | |
1092 GURL new_url; | |
1093 MergeRedirectUrlOfResponses( | |
1094 deltas, &new_url, conflicting_extensions, net_log); | |
1095 if (new_url.is_valid()) { | |
1096 // Only create a copy if we really want to modify the response headers. | |
1097 if (override_response_headers->get() == NULL) { | |
1098 *override_response_headers = new net::HttpResponseHeaders( | |
1099 original_response_headers->raw_headers()); | |
1100 } | |
1101 (*override_response_headers)->ReplaceStatusLine("HTTP/1.1 302 Found"); | |
1102 (*override_response_headers)->RemoveHeader("location"); | |
1103 (*override_response_headers)->AddHeader("Location: " + new_url.spec()); | |
1104 // Explicitly mark the URL as safe for redirection, to prevent the request | |
1105 // from being blocked because of net::ERR_UNSAFE_REDIRECT. | |
1106 *allowed_unsafe_redirect_url = new_url; | |
1107 } | |
1108 } | |
1109 | |
1110 bool MergeOnAuthRequiredResponses( | |
1111 const EventResponseDeltas& deltas, | |
1112 net::AuthCredentials* auth_credentials, | |
1113 extensions::WarningSet* conflicting_extensions, | |
1114 const net::BoundNetLog* net_log) { | |
1115 CHECK(auth_credentials); | |
1116 bool credentials_set = false; | |
1117 std::string winning_extension_id; | |
1118 | |
1119 for (EventResponseDeltas::const_iterator delta = deltas.begin(); | |
1120 delta != deltas.end(); | |
1121 ++delta) { | |
1122 if (!(*delta)->auth_credentials.get()) | |
1123 continue; | |
1124 bool different = | |
1125 auth_credentials->username() != | |
1126 (*delta)->auth_credentials->username() || | |
1127 auth_credentials->password() != (*delta)->auth_credentials->password(); | |
1128 if (credentials_set && different) { | |
1129 conflicting_extensions->insert( | |
1130 extensions::Warning::CreateCredentialsConflictWarning( | |
1131 (*delta)->extension_id, winning_extension_id)); | |
1132 net_log->AddEvent( | |
1133 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, | |
1134 CreateNetLogExtensionIdCallback(delta->get())); | |
1135 } else { | |
1136 net_log->AddEvent( | |
1137 net::NetLog::TYPE_CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS, | |
1138 CreateNetLogExtensionIdCallback(delta->get())); | |
1139 *auth_credentials = *(*delta)->auth_credentials; | |
1140 credentials_set = true; | |
1141 winning_extension_id = (*delta)->extension_id; | |
1142 } | |
1143 } | |
1144 return credentials_set; | |
1145 } | |
1146 | |
1147 void ClearCacheOnNavigation() { | |
1148 if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
1149 ClearCacheOnNavigationOnUI(); | |
1150 } else { | |
1151 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
1152 base::Bind(&ClearCacheOnNavigationOnUI)); | |
1153 } | |
1154 } | |
1155 | |
1156 void NotifyWebRequestAPIUsed( | |
1157 void* browser_context_id, | |
1158 scoped_refptr<const extensions::Extension> extension) { | |
1159 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
1160 content::BrowserContext* browser_context = | |
1161 reinterpret_cast<content::BrowserContext*>(browser_context_id); | |
1162 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext( | |
1163 browser_context)) | |
1164 return; | |
1165 | |
1166 extensions::RuntimeData* runtime_data = | |
1167 extensions::ExtensionSystem::Get(browser_context)->runtime_data(); | |
1168 if (runtime_data->HasUsedWebRequest(extension.get())) | |
1169 return; | |
1170 runtime_data->SetHasUsedWebRequest(extension.get(), true); | |
1171 | |
1172 for (content::RenderProcessHost::iterator it = | |
1173 content::RenderProcessHost::AllHostsIterator(); | |
1174 !it.IsAtEnd(); it.Advance()) { | |
1175 content::RenderProcessHost* host = it.GetCurrentValue(); | |
1176 if (host->GetBrowserContext() == browser_context) | |
1177 SendExtensionWebRequestStatusToHost(host); | |
1178 } | |
1179 } | |
1180 | |
1181 } // namespace extension_web_request_api_helpers | |
OLD | NEW |