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