// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/prerender/prerender_tracker.h" #include "base/bind.h" #include "base/logging.h" #include "chrome/browser/prerender/prerender_pending_swap_throttle.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" using content::BrowserThread; namespace prerender { PrerenderTracker::PrerenderTracker() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } PrerenderTracker::~PrerenderTracker() { } bool PrerenderTracker::IsPendingSwapRequestOnIOThread( int render_process_id, int render_frame_id, const GURL& url) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); ChildRouteIdPair render_frame_route_id_pair( render_process_id, render_frame_id); PendingSwapThrottleMap::const_iterator it = pending_swap_throttle_map_.find(render_frame_route_id_pair); return (it != pending_swap_throttle_map_.end() && it->second.url == url); } void PrerenderTracker::AddPendingSwapThrottleOnIOThread( int render_process_id, int render_frame_id, const GURL& url, const base::WeakPtr& throttle) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); ChildRouteIdPair render_frame_route_id_pair( render_process_id, render_frame_id); PendingSwapThrottleMap::iterator it = pending_swap_throttle_map_.find(render_frame_route_id_pair); DCHECK(it != pending_swap_throttle_map_.end()); if (it == pending_swap_throttle_map_.end()) return; CHECK(!it->second.throttle); it->second.throttle = throttle; } void PrerenderTracker::AddPrerenderPendingSwapOnIOThread( const ChildRouteIdPair& render_frame_route_id_pair, const GURL& url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); std::pair insert_result = pending_swap_throttle_map_.insert(std::make_pair( render_frame_route_id_pair, PendingSwapThrottleData(url))); DCHECK(insert_result.second); } void PrerenderTracker::RemovePrerenderPendingSwapOnIOThread( const ChildRouteIdPair& render_frame_route_id_pair, bool swap_successful) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); PendingSwapThrottleMap::iterator it = pending_swap_throttle_map_.find(render_frame_route_id_pair); DCHECK(it != pending_swap_throttle_map_.end()); // Cancel or resume all throttled resources. if (it->second.throttle) { if (swap_successful) it->second.throttle->Cancel(); else it->second.throttle->Resume(); } pending_swap_throttle_map_.erase(render_frame_route_id_pair); } void PrerenderTracker::AddPrerenderPendingSwap( const ChildRouteIdPair& render_frame_route_id_pair, const GURL& url) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&PrerenderTracker::AddPrerenderPendingSwapOnIOThread, base::Unretained(this), render_frame_route_id_pair, url)); } void PrerenderTracker::RemovePrerenderPendingSwap( const ChildRouteIdPair& render_frame_route_id_pair, bool swap_successful) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&PrerenderTracker::RemovePrerenderPendingSwapOnIOThread, base::Unretained(this), render_frame_route_id_pair, swap_successful)); } PrerenderTracker::PendingSwapThrottleData::PendingSwapThrottleData( const GURL& swap_url) : url(swap_url) { } PrerenderTracker::PendingSwapThrottleData::~PendingSwapThrottleData() { } scoped_refptr PrerenderTracker::GetPrerenderCookieStoreForRenderProcess( int process_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); PrerenderCookieStoreMap::const_iterator it = prerender_cookie_store_map_.find(process_id); if (it == prerender_cookie_store_map_.end()) return NULL; return it->second; } void PrerenderTracker::OnCookieChangedForURL( int process_id, net::CookieMonster* cookie_monster, const GURL& url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // We only care about cookie changes by non-prerender tabs, since only those // get applied to the underlying cookie store. Therefore, if a cookie change // originated from a prerender, there is nothing to do. if (ContainsKey(prerender_cookie_store_map_, process_id)) return; // Since the cookie change did not come from a prerender, broadcast it too // all prerenders so that they can be cancelled if there is a conflict. for (PrerenderCookieStoreMap::iterator it = prerender_cookie_store_map_.begin(); it != prerender_cookie_store_map_.end(); ++it) { it->second->OnCookieChangedForURL(cookie_monster, url); } } void PrerenderTracker::RemovePrerenderCookieStoreOnIOThread(int process_id, bool was_swapped) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); PrerenderCookieStoreMap::iterator it = prerender_cookie_store_map_.find(process_id); if (it == prerender_cookie_store_map_.end()) return; std::vector cookie_change_urls; if (was_swapped) it->second->ApplyChanges(&cookie_change_urls); scoped_refptr cookie_monster( it->second->default_cookie_monster()); prerender_cookie_store_map_.erase(it); // For each cookie updated by ApplyChanges, we need to call // OnCookieChangedForURL so that any potentially conflicting prerenders // will be aborted. for (std::vector::const_iterator url_it = cookie_change_urls.begin(); url_it != cookie_change_urls.end(); ++url_it) { OnCookieChangedForURL(process_id, cookie_monster.get(), *url_it); } } void PrerenderTracker::AddPrerenderCookieStoreOnIOThread( int process_id, scoped_refptr request_context, const base::Closure& cookie_conflict_cb) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(request_context.get() != NULL); net::CookieMonster* cookie_monster = request_context->GetURLRequestContext()->cookie_store()-> GetCookieMonster(); DCHECK(cookie_monster != NULL); bool exists = (prerender_cookie_store_map_.find(process_id) != prerender_cookie_store_map_.end()); DCHECK(!exists); if (exists) return; prerender_cookie_store_map_[process_id] = new PrerenderCookieStore(make_scoped_refptr(cookie_monster), cookie_conflict_cb); } } // namespace prerender