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