• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PrerenderTracker()19 PrerenderTracker::PrerenderTracker() {
20   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
21 }
22 
~PrerenderTracker()23 PrerenderTracker::~PrerenderTracker() {
24 }
25 
IsPendingSwapRequestOnIOThread(int render_process_id,int render_frame_id,const GURL & url) const26 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 
AddPendingSwapThrottleOnIOThread(int render_process_id,int render_frame_id,const GURL & url,const base::WeakPtr<PrerenderPendingSwapThrottle> & throttle)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 
AddPrerenderPendingSwapOnIOThread(const ChildRouteIdPair & render_frame_route_id_pair,const GURL & url)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 
RemovePrerenderPendingSwapOnIOThread(const ChildRouteIdPair & render_frame_route_id_pair,bool swap_successful)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 
AddPrerenderPendingSwap(const ChildRouteIdPair & render_frame_route_id_pair,const GURL & url)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 
RemovePrerenderPendingSwap(const ChildRouteIdPair & render_frame_route_id_pair,bool swap_successful)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 
PendingSwapThrottleData(const GURL & swap_url)101 PrerenderTracker::PendingSwapThrottleData::PendingSwapThrottleData(
102     const GURL& swap_url)
103     : url(swap_url) {
104 }
105 
~PendingSwapThrottleData()106 PrerenderTracker::PendingSwapThrottleData::~PendingSwapThrottleData() {
107 }
108 
109 scoped_refptr<PrerenderCookieStore>
GetPrerenderCookieStoreForRenderProcess(int process_id)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 
OnCookieChangedForURL(int process_id,net::CookieMonster * cookie_monster,const GURL & url)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 
RemovePrerenderCookieStoreOnIOThread(int process_id,bool was_swapped)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 
AddPrerenderCookieStoreOnIOThread(int process_id,scoped_refptr<net::URLRequestContextGetter> request_context,const base::Closure & cookie_conflict_cb)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