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