OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/prerender/prerender_resource_throttle.h" | 5 #include "chrome/browser/prerender/prerender_resource_throttle.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
9 #include "base/numerics/safe_conversions.h" | 9 #include "base/numerics/safe_conversions.h" |
10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
11 #include "chrome/browser/prerender/prerender_final_status.h" | 11 #include "chrome/browser/prerender/prerender_final_status.h" |
12 #include "chrome/browser/prerender/prerender_manager.h" | 12 #include "chrome/browser/prerender/prerender_manager.h" |
13 #include "chrome/browser/prerender/prerender_util.h" | 13 #include "chrome/browser/prerender/prerender_util.h" |
14 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
15 #include "content/public/browser/render_frame_host.h" | |
16 #include "content/public/browser/resource_request_info.h" | |
17 #include "content/public/browser/web_contents.h" | 15 #include "content/public/browser/web_contents.h" |
18 #include "net/http/http_response_headers.h" | 16 #include "net/http/http_response_headers.h" |
19 #include "net/url_request/redirect_info.h" | 17 #include "net/url_request/redirect_info.h" |
20 #include "net/url_request/url_request.h" | 18 #include "net/url_request/url_request.h" |
21 | 19 |
22 using content::BrowserThread; | 20 using content::BrowserThread; |
21 using content::ResourceRequestInfo; | |
23 using content::ResourceType; | 22 using content::ResourceType; |
24 | 23 |
25 namespace prerender { | 24 namespace prerender { |
26 | 25 |
27 namespace { | 26 namespace { |
28 static const char kFollowOnlyWhenPrerenderShown[] = | 27 static const char kFollowOnlyWhenPrerenderShown[] = |
29 "follow-only-when-prerender-shown"; | 28 "follow-only-when-prerender-shown"; |
30 | 29 |
31 PrerenderContents* g_prerender_contents_for_testing; | 30 PrerenderContents* g_prerender_contents_for_testing; |
32 | 31 |
33 // Returns true if the response has a "no-store" cache control header. | 32 // Returns true if the response has a "no-store" cache control header. |
34 bool IsNoStoreResponse(const net::URLRequest& request) { | 33 bool IsNoStoreResponse(const net::URLRequest& request) { |
35 const net::HttpResponseInfo& response_info = request.response_info(); | 34 const net::HttpResponseInfo& response_info = request.response_info(); |
36 return response_info.headers.get() && | 35 return response_info.headers.get() && |
37 response_info.headers->HasHeaderValue("cache-control", "no-store"); | 36 response_info.headers->HasHeaderValue("cache-control", "no-store"); |
38 } | 37 } |
39 | 38 |
40 } // namespace | 39 } // namespace |
41 | 40 |
42 // Used to pass information between different UI thread tasks of the same | 41 // Used to pass information between different UI thread tasks of the same |
43 // throttle. This is reference counted as the throttler may be destroyed before | 42 // throttle. This is reference counted as the throttler may be destroyed before |
44 // the UI thread task has a chance to run. | 43 // the UI thread task has a chance to run. |
45 // | 44 // |
46 // This class is created on the IO thread, and destroyed on the UI thread. Its | 45 // This class is created on the IO thread, and destroyed on the UI thread. Its |
47 // members should only be accessed on the UI thread. | 46 // members should only be accessed on the UI thread. |
48 class PrerenderThrottleInfo | 47 class PrerenderThrottleInfo |
49 : public base::RefCountedThreadSafe<PrerenderThrottleInfo, | 48 : public base::RefCountedThreadSafe<PrerenderThrottleInfo, |
50 BrowserThread::DeleteOnUIThread> { | 49 BrowserThread::DeleteOnUIThread> { |
51 public: | 50 public: |
52 PrerenderThrottleInfo() : manager_(nullptr) {} | 51 PrerenderThrottleInfo() |
52 : mode_(NO_PRERENDER), origin_(ORIGIN_NONE), manager_(nullptr) {} | |
53 | 53 |
54 void Set(PrerenderMode mode, Origin origin, PrerenderManager* manager) { | 54 void Set(PrerenderMode mode, Origin origin, PrerenderManager* manager) { |
55 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 55 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
56 mode_ = mode; | 56 mode_ = mode; |
57 origin_ = origin; | 57 origin_ = origin; |
58 manager_ = manager->AsWeakPtr(); | 58 manager_ = manager->AsWeakPtr(); |
59 } | 59 } |
60 | 60 |
61 PrerenderMode mode() const { return mode_; } | 61 PrerenderMode mode() const { return mode_; } |
62 Origin origin() const { return origin_; } | 62 Origin origin() const { return origin_; } |
(...skipping 24 matching lines...) Expand all Loading... | |
87 | 87 |
88 PrerenderResourceThrottle::~PrerenderResourceThrottle() {} | 88 PrerenderResourceThrottle::~PrerenderResourceThrottle() {} |
89 | 89 |
90 void PrerenderResourceThrottle::WillStartRequest(bool* defer) { | 90 void PrerenderResourceThrottle::WillStartRequest(bool* defer) { |
91 const content::ResourceRequestInfo* info = | 91 const content::ResourceRequestInfo* info = |
92 content::ResourceRequestInfo::ForRequest(request_); | 92 content::ResourceRequestInfo::ForRequest(request_); |
93 *defer = true; | 93 *defer = true; |
94 BrowserThread::PostTask( | 94 BrowserThread::PostTask( |
95 BrowserThread::UI, FROM_HERE, | 95 BrowserThread::UI, FROM_HERE, |
96 base::Bind(&PrerenderResourceThrottle::WillStartRequestOnUI, AsWeakPtr(), | 96 base::Bind(&PrerenderResourceThrottle::WillStartRequestOnUI, AsWeakPtr(), |
97 request_->method(), info->GetResourceType(), | 97 request_->method(), info->GetResourceType(), request_->url(), |
98 info->GetChildID(), info->GetRenderFrameID(), request_->url(), | 98 info->GetWebContentsGetterForRequest(), |
99 prerender_throttle_info_)); | 99 prerender_throttle_info_)); |
100 } | 100 } |
101 | 101 |
102 void PrerenderResourceThrottle::WillRedirectRequest( | 102 void PrerenderResourceThrottle::WillRedirectRequest( |
103 const net::RedirectInfo& redirect_info, | 103 const net::RedirectInfo& redirect_info, |
104 bool* defer) { | 104 bool* defer) { |
105 const content::ResourceRequestInfo* info = | 105 const content::ResourceRequestInfo* info = |
106 content::ResourceRequestInfo::ForRequest(request_); | 106 content::ResourceRequestInfo::ForRequest(request_); |
107 *defer = true; | 107 *defer = true; |
108 std::string header; | 108 std::string header; |
109 request_->GetResponseHeaderByName(kFollowOnlyWhenPrerenderShown, &header); | 109 request_->GetResponseHeaderByName(kFollowOnlyWhenPrerenderShown, &header); |
110 | 110 |
111 BrowserThread::PostTask( | 111 BrowserThread::PostTask( |
112 BrowserThread::UI, FROM_HERE, | 112 BrowserThread::UI, FROM_HERE, |
113 base::Bind(&PrerenderResourceThrottle::WillRedirectRequestOnUI, | 113 base::Bind(&PrerenderResourceThrottle::WillRedirectRequestOnUI, |
114 AsWeakPtr(), header, info->GetResourceType(), info->IsAsync(), | 114 AsWeakPtr(), header, info->GetResourceType(), info->IsAsync(), |
115 IsNoStoreResponse(*request_), info->GetChildID(), | 115 IsNoStoreResponse(*request_), redirect_info.new_url, |
116 info->GetRenderFrameID(), redirect_info.new_url)); | 116 info->GetWebContentsGetterForRequest())); |
117 } | 117 } |
118 | 118 |
119 void PrerenderResourceThrottle::WillProcessResponse(bool* defer) { | 119 void PrerenderResourceThrottle::WillProcessResponse(bool* defer) { |
120 const content::ResourceRequestInfo* info = | 120 const content::ResourceRequestInfo* info = |
121 content::ResourceRequestInfo::ForRequest(request_); | 121 content::ResourceRequestInfo::ForRequest(request_); |
122 if (!info) | 122 if (!info) |
123 return; | 123 return; |
124 | 124 |
125 DCHECK_GT(request_->url_chain().size(), 0u); | 125 DCHECK_GT(request_->url_chain().size(), 0u); |
126 int redirect_count = | 126 int redirect_count = |
127 base::saturated_cast<int>(request_->url_chain().size()) - 1; | 127 base::saturated_cast<int>(request_->url_chain().size()) - 1; |
128 | 128 |
129 BrowserThread::PostTask( | 129 BrowserThread::PostTask( |
130 BrowserThread::UI, FROM_HERE, | 130 BrowserThread::UI, FROM_HERE, |
131 base::Bind(&PrerenderResourceThrottle::WillProcessResponseOnUI, | 131 base::Bind(&PrerenderResourceThrottle::WillProcessResponseOnUI, |
132 content::IsResourceTypeFrame(info->GetResourceType()), | 132 content::IsResourceTypeFrame(info->GetResourceType()), |
133 IsNoStoreResponse(*request_), redirect_count, | 133 IsNoStoreResponse(*request_), redirect_count, |
134 info->GetChildID(), info->GetRenderFrameID(), | |
135 prerender_throttle_info_)); | 134 prerender_throttle_info_)); |
136 } | 135 } |
137 | 136 |
138 const char* PrerenderResourceThrottle::GetNameForLogging() const { | 137 const char* PrerenderResourceThrottle::GetNameForLogging() const { |
139 return "PrerenderResourceThrottle"; | 138 return "PrerenderResourceThrottle"; |
140 } | 139 } |
141 | 140 |
142 void PrerenderResourceThrottle::ResumeHandler() { | 141 void PrerenderResourceThrottle::ResumeHandler() { |
143 Resume(); | 142 Resume(); |
144 } | 143 } |
145 | 144 |
146 // static | 145 // static |
147 void PrerenderResourceThrottle::WillStartRequestOnUI( | 146 void PrerenderResourceThrottle::WillStartRequestOnUI( |
148 const base::WeakPtr<PrerenderResourceThrottle>& throttle, | 147 const base::WeakPtr<PrerenderResourceThrottle>& throttle, |
149 const std::string& method, | 148 const std::string& method, |
150 ResourceType resource_type, | 149 ResourceType resource_type, |
151 int render_process_id, | |
152 int render_frame_id, | |
153 const GURL& url, | 150 const GURL& url, |
151 const ResourceRequestInfo::WebContentsGetter& web_contents_getter, | |
154 scoped_refptr<PrerenderThrottleInfo> prerender_throttle_info) { | 152 scoped_refptr<PrerenderThrottleInfo> prerender_throttle_info) { |
155 bool cancel = false; | 153 bool cancel = false; |
156 PrerenderContents* prerender_contents = | 154 PrerenderContents* prerender_contents = |
157 PrerenderContentsFromRenderFrame(render_process_id, render_frame_id); | 155 PrerenderContentsFromGetter(web_contents_getter); |
158 if (prerender_contents) { | 156 if (prerender_contents) { |
159 DCHECK(prerender_throttle_info); | 157 DCHECK(prerender_throttle_info); |
160 prerender_throttle_info->Set(prerender_contents->prerender_mode(), | 158 prerender_throttle_info->Set(prerender_contents->prerender_mode(), |
161 prerender_contents->origin(), | 159 prerender_contents->origin(), |
162 prerender_contents->prerender_manager()); | 160 prerender_contents->prerender_manager()); |
163 | 161 |
164 // Abort any prerenders that spawn requests that use unsupported HTTP | 162 // Abort any prerenders that spawn requests that use unsupported HTTP |
165 // methods or schemes. | 163 // methods or schemes. |
166 if (!prerender_contents->IsValidHttpMethod(method)) { | 164 if (!prerender_contents->IsValidHttpMethod(method)) { |
167 // If this is a full prerender, cancel the prerender in response to | 165 // If this is a full prerender, cancel the prerender in response to |
168 // invalid requests. For prefetches, cancel invalid requests but keep the | 166 // invalid requests. For prefetches, cancel invalid requests but keep the |
169 // prefetch going, unless it's the main frame that's invalid. | 167 // prefetch going, unless it's the main frame that's invalid. |
170 if (prerender_contents->prerender_mode() == FULL_PRERENDER || | 168 if (prerender_contents->prerender_mode() == FULL_PRERENDER || |
171 resource_type == content::RESOURCE_TYPE_MAIN_FRAME) { | 169 resource_type == content::RESOURCE_TYPE_MAIN_FRAME) { |
172 prerender_contents->Destroy(FINAL_STATUS_INVALID_HTTP_METHOD); | 170 prerender_contents->Destroy(FINAL_STATUS_INVALID_HTTP_METHOD); |
173 } | 171 } |
174 cancel = true; | 172 cancel = true; |
175 } else if (!PrerenderManager::DoesSubresourceURLHaveValidScheme(url)) { | 173 } else if (!PrerenderManager::DoesSubresourceURLHaveValidScheme(url) && |
174 resource_type != content::RESOURCE_TYPE_MAIN_FRAME) { | |
droger
2016/12/15 09:46:21
This is the one line fix for the failing tests.
T
pasko
2016/12/15 15:25:45
Thanks. That's very informative! Can we put a comm
droger
2016/12/15 16:25:01
Done.
Note also that DoesSubresourceURLHaveValidS
| |
176 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); | 175 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); |
177 ReportUnsupportedPrerenderScheme(url); | 176 ReportUnsupportedPrerenderScheme(url); |
178 cancel = true; | 177 cancel = true; |
179 #if defined(OS_ANDROID) | 178 #if defined(OS_ANDROID) |
180 } else if (resource_type == content::RESOURCE_TYPE_FAVICON) { | 179 } else if (resource_type == content::RESOURCE_TYPE_FAVICON) { |
181 // Delay icon fetching until the contents are getting swapped in | 180 // Delay icon fetching until the contents are getting swapped in |
182 // to conserve network usage in mobile devices. | 181 // to conserve network usage in mobile devices. |
183 prerender_contents->AddResourceThrottle(throttle); | 182 prerender_contents->AddResourceThrottle(throttle); |
184 return; | 183 return; |
185 #endif | 184 #endif |
186 } | 185 } |
187 } | 186 } |
188 | 187 |
189 BrowserThread::PostTask( | 188 BrowserThread::PostTask( |
190 BrowserThread::IO, FROM_HERE, | 189 BrowserThread::IO, FROM_HERE, |
191 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel | 190 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel |
192 : &PrerenderResourceThrottle::ResumeHandler, | 191 : &PrerenderResourceThrottle::ResumeHandler, |
193 throttle)); | 192 throttle)); |
194 } | 193 } |
195 | 194 |
196 // static | 195 // static |
197 void PrerenderResourceThrottle::WillRedirectRequestOnUI( | 196 void PrerenderResourceThrottle::WillRedirectRequestOnUI( |
198 const base::WeakPtr<PrerenderResourceThrottle>& throttle, | 197 const base::WeakPtr<PrerenderResourceThrottle>& throttle, |
199 const std::string& follow_only_when_prerender_shown_header, | 198 const std::string& follow_only_when_prerender_shown_header, |
200 ResourceType resource_type, | 199 ResourceType resource_type, |
201 bool async, | 200 bool async, |
202 bool is_no_store, | 201 bool is_no_store, |
203 int render_process_id, | 202 const GURL& new_url, |
204 int render_frame_id, | 203 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) { |
205 const GURL& new_url) { | |
206 bool cancel = false; | 204 bool cancel = false; |
207 PrerenderContents* prerender_contents = | 205 PrerenderContents* prerender_contents = |
208 PrerenderContentsFromRenderFrame(render_process_id, render_frame_id); | 206 PrerenderContentsFromGetter(web_contents_getter); |
209 if (prerender_contents) { | 207 if (prerender_contents) { |
210 prerender_contents->prerender_manager()->RecordPrefetchResponseReceived( | 208 prerender_contents->prerender_manager()->RecordPrefetchResponseReceived( |
211 prerender_contents->origin(), | 209 prerender_contents->origin(), |
212 content::IsResourceTypeFrame(resource_type), true /* is_redirect */, | 210 content::IsResourceTypeFrame(resource_type), true /* is_redirect */, |
213 is_no_store); | 211 is_no_store); |
214 // Abort any prerenders with requests which redirect to invalid schemes. | 212 // Abort any prerenders with requests which redirect to invalid schemes. |
215 if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) { | 213 if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) { |
216 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); | 214 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); |
217 ReportUnsupportedPrerenderScheme(new_url); | 215 ReportUnsupportedPrerenderScheme(new_url); |
218 cancel = true; | 216 cancel = true; |
(...skipping 19 matching lines...) Expand all Loading... | |
238 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel | 236 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel |
239 : &PrerenderResourceThrottle::ResumeHandler, | 237 : &PrerenderResourceThrottle::ResumeHandler, |
240 throttle)); | 238 throttle)); |
241 } | 239 } |
242 | 240 |
243 // static | 241 // static |
244 void PrerenderResourceThrottle::WillProcessResponseOnUI( | 242 void PrerenderResourceThrottle::WillProcessResponseOnUI( |
245 bool is_main_resource, | 243 bool is_main_resource, |
246 bool is_no_store, | 244 bool is_no_store, |
247 int redirect_count, | 245 int redirect_count, |
248 int render_process_id, | |
249 int render_frame_id, | |
250 scoped_refptr<PrerenderThrottleInfo> prerender_throttle_info) { | 246 scoped_refptr<PrerenderThrottleInfo> prerender_throttle_info) { |
251 DCHECK(prerender_throttle_info); | 247 DCHECK(prerender_throttle_info); |
252 if (!prerender_throttle_info->manager()) | 248 if (!prerender_throttle_info->manager()) |
253 return; | 249 return; |
254 | 250 |
255 if (prerender_throttle_info->mode() != PREFETCH_ONLY) | 251 if (prerender_throttle_info->mode() != PREFETCH_ONLY) |
256 return; | 252 return; |
257 | 253 |
258 prerender_throttle_info->manager()->RecordPrefetchResponseReceived( | 254 prerender_throttle_info->manager()->RecordPrefetchResponseReceived( |
259 prerender_throttle_info->origin(), is_main_resource, | 255 prerender_throttle_info->origin(), is_main_resource, |
260 false /* is_redirect */, is_no_store); | 256 false /* is_redirect */, is_no_store); |
261 prerender_throttle_info->manager()->RecordPrefetchRedirectCount( | 257 prerender_throttle_info->manager()->RecordPrefetchRedirectCount( |
262 prerender_throttle_info->origin(), is_main_resource, redirect_count); | 258 prerender_throttle_info->origin(), is_main_resource, redirect_count); |
263 } | 259 } |
264 | 260 |
265 // static | 261 // static |
266 PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromRenderFrame( | 262 PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromGetter( |
267 int render_process_id, int render_frame_id) { | 263 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) { |
268 if (g_prerender_contents_for_testing) | 264 if (g_prerender_contents_for_testing) |
269 return g_prerender_contents_for_testing; | 265 return g_prerender_contents_for_testing; |
270 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( | 266 return PrerenderContents::FromWebContents(web_contents_getter.Run()); |
271 render_process_id, render_frame_id); | |
272 content::WebContents* web_contents = | |
273 content::WebContents::FromRenderFrameHost(rfh); | |
274 return PrerenderContents::FromWebContents(web_contents); | |
275 } | 267 } |
276 | 268 |
277 } // namespace prerender | 269 } // namespace prerender |
OLD | NEW |