Home | History | Annotate | Download | only in prerender
      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/prerender/prerender_tracker.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "chrome/browser/prerender/prerender_pending_swap_throttle.h"
     10 #include "content/public/browser/browser_thread.h"
     11 #include "content/public/browser/render_process_host.h"
     12 #include "net/url_request/url_request_context.h"
     13 #include "net/url_request/url_request_context_getter.h"
     14 
     15 using content::BrowserThread;
     16 
     17 namespace prerender {
     18 
     19 PrerenderTracker::PrerenderTracker() {
     20   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     21 }
     22 
     23 PrerenderTracker::~PrerenderTracker() {
     24 }
     25 
     26 bool PrerenderTracker::IsPendingSwapRequestOnIOThread(
     27     int render_process_id, int render_frame_id, const GURL& url) const {
     28   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     29 
     30   ChildRouteIdPair render_frame_route_id_pair(
     31       render_process_id, render_frame_id);
     32   PendingSwapThrottleMap::const_iterator it =
     33       pending_swap_throttle_map_.find(render_frame_route_id_pair);
     34   return (it != pending_swap_throttle_map_.end() && it->second.url == url);
     35 }
     36 
     37 void PrerenderTracker::AddPendingSwapThrottleOnIOThread(
     38     int render_process_id,
     39     int render_frame_id,
     40     const GURL& url,
     41     const base::WeakPtr<PrerenderPendingSwapThrottle>& throttle) {
     42   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     43 
     44   ChildRouteIdPair render_frame_route_id_pair(
     45       render_process_id, render_frame_id);
     46   PendingSwapThrottleMap::iterator it =
     47       pending_swap_throttle_map_.find(render_frame_route_id_pair);
     48   DCHECK(it != pending_swap_throttle_map_.end());
     49   if (it == pending_swap_throttle_map_.end())
     50     return;
     51   CHECK(!it->second.throttle);
     52   it->second.throttle = throttle;
     53 }
     54 
     55 void PrerenderTracker::AddPrerenderPendingSwapOnIOThread(
     56     const ChildRouteIdPair& render_frame_route_id_pair,
     57     const GURL& url) {
     58   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     59   std::pair<PendingSwapThrottleMap::iterator, bool> insert_result =
     60       pending_swap_throttle_map_.insert(std::make_pair(
     61           render_frame_route_id_pair, PendingSwapThrottleData(url)));
     62   DCHECK(insert_result.second);
     63 }
     64 
     65 void PrerenderTracker::RemovePrerenderPendingSwapOnIOThread(
     66     const ChildRouteIdPair& render_frame_route_id_pair,
     67     bool swap_successful) {
     68   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     69   PendingSwapThrottleMap::iterator it =
     70       pending_swap_throttle_map_.find(render_frame_route_id_pair);
     71   DCHECK(it != pending_swap_throttle_map_.end());
     72   // Cancel or resume all throttled resources.
     73   if (it->second.throttle) {
     74     if (swap_successful)
     75       it->second.throttle->Cancel();
     76     else
     77       it->second.throttle->Resume();
     78   }
     79   pending_swap_throttle_map_.erase(render_frame_route_id_pair);
     80 }
     81 
     82 void PrerenderTracker::AddPrerenderPendingSwap(
     83     const ChildRouteIdPair& render_frame_route_id_pair,
     84     const GURL& url) {
     85   BrowserThread::PostTask(
     86       BrowserThread::IO, FROM_HERE,
     87       base::Bind(&PrerenderTracker::AddPrerenderPendingSwapOnIOThread,
     88                  base::Unretained(this), render_frame_route_id_pair, url));
     89 }
     90 
     91 void PrerenderTracker::RemovePrerenderPendingSwap(
     92     const ChildRouteIdPair& render_frame_route_id_pair,
     93     bool swap_successful) {
     94   BrowserThread::PostTask(
     95       BrowserThread::IO, FROM_HERE,
     96       base::Bind(&PrerenderTracker::RemovePrerenderPendingSwapOnIOThread,
     97                  base::Unretained(this), render_frame_route_id_pair,
     98                  swap_successful));
     99 }
    100 
    101 PrerenderTracker::PendingSwapThrottleData::PendingSwapThrottleData(
    102     const GURL& swap_url)
    103     : url(swap_url) {
    104 }
    105 
    106 PrerenderTracker::PendingSwapThrottleData::~PendingSwapThrottleData() {
    107 }
    108 
    109 scoped_refptr<PrerenderCookieStore>
    110 PrerenderTracker::GetPrerenderCookieStoreForRenderProcess(
    111     int process_id) {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    113   PrerenderCookieStoreMap::const_iterator it =
    114       prerender_cookie_store_map_.find(process_id);
    115 
    116   if (it == prerender_cookie_store_map_.end())
    117     return NULL;
    118 
    119   return it->second;
    120 }
    121 
    122 void PrerenderTracker::OnCookieChangedForURL(
    123     int process_id,
    124     net::CookieMonster* cookie_monster,
    125     const GURL& url) {
    126   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    127 
    128   // We only care about cookie changes by non-prerender tabs, since only those
    129   // get applied to the underlying cookie store. Therefore, if a cookie change
    130   // originated from a prerender, there is nothing to do.
    131   if (ContainsKey(prerender_cookie_store_map_, process_id))
    132     return;
    133 
    134   // Since the cookie change did not come from a prerender, broadcast it too
    135   // all prerenders so that they can be cancelled if there is a conflict.
    136   for (PrerenderCookieStoreMap::iterator it =
    137            prerender_cookie_store_map_.begin();
    138        it != prerender_cookie_store_map_.end();
    139        ++it) {
    140     it->second->OnCookieChangedForURL(cookie_monster, url);
    141   }
    142 }
    143 
    144 void PrerenderTracker::RemovePrerenderCookieStoreOnIOThread(int process_id,
    145                                                             bool was_swapped) {
    146   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    147 
    148   PrerenderCookieStoreMap::iterator it =
    149       prerender_cookie_store_map_.find(process_id);
    150 
    151   if (it == prerender_cookie_store_map_.end())
    152     return;
    153 
    154   std::vector<GURL> cookie_change_urls;
    155   if (was_swapped)
    156     it->second->ApplyChanges(&cookie_change_urls);
    157 
    158   scoped_refptr<net::CookieMonster> cookie_monster(
    159       it->second->default_cookie_monster());
    160 
    161   prerender_cookie_store_map_.erase(it);
    162 
    163   // For each cookie updated by ApplyChanges, we need to call
    164   // OnCookieChangedForURL so that any potentially conflicting prerenders
    165   // will be aborted.
    166   for (std::vector<GURL>::const_iterator url_it = cookie_change_urls.begin();
    167        url_it != cookie_change_urls.end();
    168        ++url_it) {
    169     OnCookieChangedForURL(process_id, cookie_monster.get(), *url_it);
    170   }
    171 }
    172 
    173 void PrerenderTracker::AddPrerenderCookieStoreOnIOThread(
    174     int process_id,
    175     scoped_refptr<net::URLRequestContextGetter> request_context,
    176     const base::Closure& cookie_conflict_cb) {
    177   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    178   DCHECK(request_context.get() != NULL);
    179   net::CookieMonster* cookie_monster =
    180       request_context->GetURLRequestContext()->cookie_store()->
    181       GetCookieMonster();
    182   DCHECK(cookie_monster != NULL);
    183   bool exists = (prerender_cookie_store_map_.find(process_id) !=
    184                  prerender_cookie_store_map_.end());
    185   DCHECK(!exists);
    186   if (exists)
    187     return;
    188   prerender_cookie_store_map_[process_id] =
    189       new PrerenderCookieStore(make_scoped_refptr(cookie_monster),
    190                                cookie_conflict_cb);
    191 }
    192 
    193 }  // namespace prerender
    194