| 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) { |
| 175 // Destroying the prerender for unsupported scheme only for non-main |
| 176 // resource to allow chrome://crash to actually crash in the |
| 177 // *RendererCrash tests instead of being intercepted here. The unsupported |
| 178 // scheme for the main resource is checked in WillRedirectRequestOnUI() |
| 179 // and PrerenderContents::CheckURL(). See http://crbug.com/673771. |
| 176 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); | 180 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); |
| 177 ReportUnsupportedPrerenderScheme(url); | 181 ReportUnsupportedPrerenderScheme(url); |
| 178 cancel = true; | 182 cancel = true; |
| 179 #if defined(OS_ANDROID) | 183 #if defined(OS_ANDROID) |
| 180 } else if (resource_type == content::RESOURCE_TYPE_FAVICON) { | 184 } else if (resource_type == content::RESOURCE_TYPE_FAVICON) { |
| 181 // Delay icon fetching until the contents are getting swapped in | 185 // Delay icon fetching until the contents are getting swapped in |
| 182 // to conserve network usage in mobile devices. | 186 // to conserve network usage in mobile devices. |
| 183 prerender_contents->AddResourceThrottle(throttle); | 187 prerender_contents->AddResourceThrottle(throttle); |
| 184 return; | 188 return; |
| 185 #endif | 189 #endif |
| 186 } | 190 } |
| 187 } | 191 } |
| 188 | 192 |
| 189 BrowserThread::PostTask( | 193 BrowserThread::PostTask( |
| 190 BrowserThread::IO, FROM_HERE, | 194 BrowserThread::IO, FROM_HERE, |
| 191 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel | 195 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel |
| 192 : &PrerenderResourceThrottle::ResumeHandler, | 196 : &PrerenderResourceThrottle::ResumeHandler, |
| 193 throttle)); | 197 throttle)); |
| 194 } | 198 } |
| 195 | 199 |
| 196 // static | 200 // static |
| 197 void PrerenderResourceThrottle::WillRedirectRequestOnUI( | 201 void PrerenderResourceThrottle::WillRedirectRequestOnUI( |
| 198 const base::WeakPtr<PrerenderResourceThrottle>& throttle, | 202 const base::WeakPtr<PrerenderResourceThrottle>& throttle, |
| 199 const std::string& follow_only_when_prerender_shown_header, | 203 const std::string& follow_only_when_prerender_shown_header, |
| 200 ResourceType resource_type, | 204 ResourceType resource_type, |
| 201 bool async, | 205 bool async, |
| 202 bool is_no_store, | 206 bool is_no_store, |
| 203 int render_process_id, | 207 const GURL& new_url, |
| 204 int render_frame_id, | 208 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) { |
| 205 const GURL& new_url) { | |
| 206 bool cancel = false; | 209 bool cancel = false; |
| 207 PrerenderContents* prerender_contents = | 210 PrerenderContents* prerender_contents = |
| 208 PrerenderContentsFromRenderFrame(render_process_id, render_frame_id); | 211 PrerenderContentsFromGetter(web_contents_getter); |
| 209 if (prerender_contents) { | 212 if (prerender_contents) { |
| 210 prerender_contents->prerender_manager()->RecordPrefetchResponseReceived( | 213 prerender_contents->prerender_manager()->RecordPrefetchResponseReceived( |
| 211 prerender_contents->origin(), | 214 prerender_contents->origin(), |
| 212 content::IsResourceTypeFrame(resource_type), true /* is_redirect */, | 215 content::IsResourceTypeFrame(resource_type), true /* is_redirect */, |
| 213 is_no_store); | 216 is_no_store); |
| 214 // Abort any prerenders with requests which redirect to invalid schemes. | 217 // Abort any prerenders with requests which redirect to invalid schemes. |
| 215 if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) { | 218 if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) { |
| 216 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); | 219 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME); |
| 217 ReportUnsupportedPrerenderScheme(new_url); | 220 ReportUnsupportedPrerenderScheme(new_url); |
| 218 cancel = true; | 221 cancel = true; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 238 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel | 241 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel |
| 239 : &PrerenderResourceThrottle::ResumeHandler, | 242 : &PrerenderResourceThrottle::ResumeHandler, |
| 240 throttle)); | 243 throttle)); |
| 241 } | 244 } |
| 242 | 245 |
| 243 // static | 246 // static |
| 244 void PrerenderResourceThrottle::WillProcessResponseOnUI( | 247 void PrerenderResourceThrottle::WillProcessResponseOnUI( |
| 245 bool is_main_resource, | 248 bool is_main_resource, |
| 246 bool is_no_store, | 249 bool is_no_store, |
| 247 int redirect_count, | 250 int redirect_count, |
| 248 int render_process_id, | |
| 249 int render_frame_id, | |
| 250 scoped_refptr<PrerenderThrottleInfo> prerender_throttle_info) { | 251 scoped_refptr<PrerenderThrottleInfo> prerender_throttle_info) { |
| 251 DCHECK(prerender_throttle_info); | 252 DCHECK(prerender_throttle_info); |
| 252 if (!prerender_throttle_info->manager()) | 253 if (!prerender_throttle_info->manager()) |
| 253 return; | 254 return; |
| 254 | 255 |
| 255 if (prerender_throttle_info->mode() != PREFETCH_ONLY) | 256 if (prerender_throttle_info->mode() != PREFETCH_ONLY) |
| 256 return; | 257 return; |
| 257 | 258 |
| 258 prerender_throttle_info->manager()->RecordPrefetchResponseReceived( | 259 prerender_throttle_info->manager()->RecordPrefetchResponseReceived( |
| 259 prerender_throttle_info->origin(), is_main_resource, | 260 prerender_throttle_info->origin(), is_main_resource, |
| 260 false /* is_redirect */, is_no_store); | 261 false /* is_redirect */, is_no_store); |
| 261 prerender_throttle_info->manager()->RecordPrefetchRedirectCount( | 262 prerender_throttle_info->manager()->RecordPrefetchRedirectCount( |
| 262 prerender_throttle_info->origin(), is_main_resource, redirect_count); | 263 prerender_throttle_info->origin(), is_main_resource, redirect_count); |
| 263 } | 264 } |
| 264 | 265 |
| 265 // static | 266 // static |
| 266 PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromRenderFrame( | 267 PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromGetter( |
| 267 int render_process_id, int render_frame_id) { | 268 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) { |
| 268 if (g_prerender_contents_for_testing) | 269 if (g_prerender_contents_for_testing) |
| 269 return g_prerender_contents_for_testing; | 270 return g_prerender_contents_for_testing; |
| 270 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( | 271 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 } | 272 } |
| 276 | 273 |
| 277 } // namespace prerender | 274 } // namespace prerender |
| OLD | NEW |