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, *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 != 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