blob: de1ec588f202ad2f0a5ff05732241301b8fd52c2 [file] [log] [blame]
[email protected]ce2fcd9202012-01-06 18:42:501// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]33f74972010-12-08 16:40:362// 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_contents.h"
6
[email protected]c49147c32011-04-26 18:42:047#include <algorithm>
[email protected]48055042012-07-14 21:12:118#include <functional>
[email protected]b99b13b2011-05-04 20:59:049#include <utility>
[email protected]c49147c32011-04-26 18:42:0410
[email protected]e309f312013-06-07 21:50:0811#include "base/strings/utf_string_conversions.h"
[email protected]b97d2a87ce2013-03-01 02:57:5912#include "chrome/browser/favicon/favicon_tab_helper.h"
[email protected]02b9b2b6f2011-05-24 17:27:5013#include "chrome/browser/history/history_tab_helper.h"
[email protected]2fc4da92011-05-27 16:24:3114#include "chrome/browser/history/history_types.h"
[email protected]db6c4ea2013-06-14 17:53:0115#include "chrome/browser/prerender/prerender_field_trial.h"
[email protected]4c154ff82011-02-15 11:23:5916#include "chrome/browser/prerender/prerender_final_status.h"
[email protected]48055042012-07-14 21:12:1117#include "chrome/browser/prerender/prerender_handle.h"
[email protected]33f74972010-12-08 16:40:3618#include "chrome/browser/prerender/prerender_manager.h"
[email protected]3b023e22011-06-16 22:53:1319#include "chrome/browser/prerender/prerender_render_view_host_observer.h"
[email protected]28a05f3a2011-05-20 15:05:0820#include "chrome/browser/prerender/prerender_tracker.h"
[email protected]cafe4ad2011-07-28 18:34:5621#include "chrome/browser/profiles/profile.h"
[email protected]a562aea22012-12-11 22:43:1222#include "chrome/browser/ui/browser.h"
[email protected]27e5b3912012-12-16 00:45:3723#include "chrome/browser/ui/browser_tab_contents.h"
[email protected]432115822011-07-10 15:52:2724#include "chrome/common/chrome_notification_types.h"
[email protected]a0358d72012-03-09 14:06:5025#include "chrome/common/prerender_messages.h"
[email protected]39365212011-02-24 01:01:0026#include "chrome/common/url_constants.h"
[email protected]458433c2012-02-29 23:43:3927#include "content/public/browser/browser_child_process_host.h"
[email protected]ad50def52011-10-19 23:17:0728#include "content/public/browser/notification_service.h"
[email protected]d9083482012-01-06 00:38:4629#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3330#include "content/public/browser/render_view_host.h"
[email protected]853e01b2012-09-21 20:14:1131#include "content/public/browser/resource_request_details.h"
[email protected]48055042012-07-14 21:12:1132#include "content/public/browser/session_storage_namespace.h"
[email protected]d9083482012-01-06 00:38:4633#include "content/public/browser/web_contents.h"
[email protected]674bc592011-12-20 23:00:4234#include "content/public/browser/web_contents_delegate.h"
[email protected]8643e6d2012-01-18 20:26:1035#include "content/public/browser/web_contents_view.h"
[email protected]795c28972012-12-06 06:13:3936#include "content/public/common/favicon_url.h"
[email protected]08397d52011-02-05 01:53:3837#include "ui/gfx/rect.h"
[email protected]33f74972010-12-08 16:40:3638
[email protected]e582fdd2011-12-20 16:48:1739using content::DownloadItem;
[email protected]e5d549d2011-12-28 01:29:2040using content::OpenURLParams;
[email protected]eaabba22012-03-07 15:02:1141using content::RenderViewHost;
[email protected]48227592012-03-19 13:13:4442using content::ResourceRedirectDetails;
[email protected]48055042012-07-14 21:12:1143using content::SessionStorageNamespace;
[email protected]768c5472011-12-26 19:06:1744using content::WebContents;
[email protected]e582fdd2011-12-20 16:48:1745
[email protected]4c154ff82011-02-15 11:23:5946namespace prerender {
47
[email protected]5a8dffa2011-01-26 00:40:3948class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
49 public:
50 virtual PrerenderContents* CreatePrerenderContents(
[email protected]ac4f4682012-12-08 22:39:2651 PrerenderManager* prerender_manager, Profile* profile,
52 const GURL& url, const content::Referrer& referrer,
[email protected]e253ab02011-07-07 21:58:3953 Origin origin, uint8 experiment_id) OVERRIDE {
[email protected]ac4f4682012-12-08 22:39:2654 return new PrerenderContents(prerender_manager, profile,
[email protected]e253ab02011-07-07 21:58:3955 url, referrer, origin, experiment_id);
[email protected]5a8dffa2011-01-26 00:40:3956 }
57};
58
[email protected]a562aea22012-12-11 22:43:1259// WebContentsDelegateImpl -----------------------------------------------------
[email protected]d3961e82011-05-20 06:32:0360
[email protected]a562aea22012-12-11 22:43:1261class PrerenderContents::WebContentsDelegateImpl
[email protected]674bc592011-12-20 23:00:4262 : public content::WebContentsDelegate {
[email protected]d3961e82011-05-20 06:32:0363 public:
[email protected]75d90c12013-03-20 19:50:1664 explicit WebContentsDelegateImpl(PrerenderContents* prerender_contents)
65 : prerender_contents_(prerender_contents) {
[email protected]d3961e82011-05-20 06:32:0366 }
[email protected]3b023e22011-06-16 22:53:1367
[email protected]baece6c32012-06-25 21:22:4168 // content::WebContentsDelegate implementation:
69 virtual WebContents* OpenURLFromTab(WebContents* source,
[email protected]48055042012-07-14 21:12:1170 const OpenURLParams& params) OVERRIDE {
[email protected]0905b01662011-12-05 20:30:2271 // |OpenURLFromTab| is typically called when a frame performs a navigation
72 // that requires the browser to perform the transition instead of WebKit.
73 // Examples include prerendering a site that redirects to an app URL,
74 // or if --enable-strict-site-isolation is specified and the prerendered
75 // frame redirects to a different origin.
[email protected]baece6c32012-06-25 21:22:4176 // TODO(cbentzel): Consider supporting this if it is a common case during
77 // prerenders.
[email protected]0905b01662011-12-05 20:30:2278 prerender_contents_->Destroy(FINAL_STATUS_OPEN_URL);
79 return NULL;
80 }
81
[email protected]f85f5032013-04-03 09:01:5482 virtual void CanDownload(
83 RenderViewHost* render_view_host,
84 int request_id,
85 const std::string& request_method,
86 const base::Callback<void(bool)>& callback) OVERRIDE {
[email protected]686493142011-07-15 21:47:2287 prerender_contents_->Destroy(FINAL_STATUS_DOWNLOAD);
88 // Cancel the download.
[email protected]f85f5032013-04-03 09:01:5489 callback.Run(false);
[email protected]686493142011-07-15 21:47:2290 }
91
[email protected]4fdf6742012-01-10 20:14:3692 virtual bool ShouldCreateWebContents(
93 WebContents* web_contents,
94 int route_id,
95 WindowContainerType window_container_type,
[email protected]03b6d552012-03-29 04:03:0196 const string16& frame_name,
97 const GURL& target_url) OVERRIDE {
[email protected]4fdf6742012-01-10 20:14:3698 // Since we don't want to permit child windows that would have a
99 // window.opener property, terminate prerendering.
100 prerender_contents_->Destroy(FINAL_STATUS_CREATE_NEW_WINDOW);
101 // Cancel the popup.
102 return false;
103 }
104
[email protected]9e1ad4b2011-08-14 16:49:19105 virtual bool OnGoToEntryOffset(int offset) OVERRIDE {
106 // This isn't allowed because the history merge operation
107 // does not work if there are renderer issued challenges.
108 // TODO(cbentzel): Cancel in this case? May not need to do
109 // since render-issued offset navigations are not guaranteed,
110 // but indicates that the page cares about the history.
111 return false;
112 }
113
[email protected]2a6bc3e2011-12-28 23:51:33114 virtual void JSOutOfMemory(WebContents* tab) OVERRIDE {
[email protected]baece6c32012-06-25 21:22:41115 prerender_contents_->Destroy(FINAL_STATUS_JS_OUT_OF_MEMORY);
[email protected]5f5b9e4cf2011-09-07 21:26:05116 }
117
118 virtual bool ShouldSuppressDialogs() OVERRIDE {
[email protected]baece6c32012-06-25 21:22:41119 // We still want to show the user the message when they navigate to this
120 // page, so cancel this prerender.
121 prerender_contents_->Destroy(FINAL_STATUS_JAVASCRIPT_ALERT);
[email protected]a562aea22012-12-11 22:43:12122 // Always suppress JavaScript messages if they're triggered by a page being
123 // prerendered.
[email protected]baece6c32012-06-25 21:22:41124 return true;
125 }
126
127 virtual void RegisterProtocolHandler(WebContents* web_contents,
128 const std::string& protocol,
129 const GURL& url,
130 const string16& title,
131 bool user_gesture) OVERRIDE {
132 // TODO(mmenke): Consider supporting this if it is a common case during
133 // prerenders.
134 prerender_contents_->Destroy(FINAL_STATUS_REGISTER_PROTOCOL_HANDLER);
[email protected]5f5b9e4cf2011-09-07 21:26:05135 }
136
[email protected]d3961e82011-05-20 06:32:03137 private:
[email protected]d3961e82011-05-20 06:32:03138 PrerenderContents* prerender_contents_;
139};
140
[email protected]49fc07b2013-01-03 21:05:22141void PrerenderContents::Observer::OnPrerenderStopLoading(
142 PrerenderContents* contents) {
143}
144
[email protected]26101702012-12-15 21:45:18145void PrerenderContents::Observer::OnPrerenderCreatedMatchCompleteReplacement(
146 PrerenderContents* contents, PrerenderContents* replacement) {
147}
148
[email protected]ac4f4682012-12-08 22:39:26149PrerenderContents::Observer::Observer() {
150}
151
152PrerenderContents::Observer::~Observer() {
153}
154
[email protected]ba17cdb2012-11-30 02:12:04155PrerenderContents::PendingPrerenderInfo::PendingPrerenderInfo(
156 base::WeakPtr<PrerenderHandle> weak_prerender_handle,
157 Origin origin,
[email protected]48055042012-07-14 21:12:11158 const GURL& url,
159 const content::Referrer& referrer,
[email protected]75d90c12013-03-20 19:50:16160 const gfx::Size& size)
161 : weak_prerender_handle(weak_prerender_handle),
162 origin(origin),
163 url(url),
164 referrer(referrer),
165 size(size) {
[email protected]829c2b82011-09-26 17:12:18166}
167
[email protected]ba17cdb2012-11-30 02:12:04168PrerenderContents::PendingPrerenderInfo::~PendingPrerenderInfo() {
169}
170
171void PrerenderContents::AddPendingPrerender(
172 scoped_ptr<PendingPrerenderInfo> pending_prerender_info) {
173 pending_prerenders_.push_back(pending_prerender_info.release());
[email protected]829c2b82011-09-26 17:12:18174}
175
[email protected]26101702012-12-15 21:45:18176void PrerenderContents::PrepareForUse() {
177 NotifyPrerenderStop();
178
[email protected]48055042012-07-14 21:12:11179 SessionStorageNamespace* session_storage_namespace = NULL;
[email protected]ba17cdb2012-11-30 02:12:04180 if (prerender_contents_) {
[email protected]d1198fd2012-08-13 22:50:19181 // TODO(ajwong): This does not correctly handle storage for isolated apps.
[email protected]a562aea22012-12-11 22:43:12182 session_storage_namespace = prerender_contents_->
183 GetController().GetDefaultSessionStorageNamespace();
[email protected]d1198fd2012-08-13 22:50:19184 }
[email protected]ba17cdb2012-11-30 02:12:04185 prerender_manager_->StartPendingPrerenders(
186 child_id_, &pending_prerenders_, session_storage_namespace);
187 pending_prerenders_.clear();
[email protected]48055042012-07-14 21:12:11188}
189
[email protected]6ee98ea42011-11-02 20:28:37190PrerenderContents::PrerenderContents(
191 PrerenderManager* prerender_manager,
[email protected]6ee98ea42011-11-02 20:28:37192 Profile* profile,
193 const GURL& url,
[email protected]5ffbf692011-12-06 00:17:51194 const content::Referrer& referrer,
[email protected]6ee98ea42011-11-02 20:28:37195 Origin origin,
196 uint8 experiment_id)
[email protected]115ab7b2012-05-16 20:25:59197 : prerendering_has_started_(false),
198 prerender_manager_(prerender_manager),
[email protected]33f74972010-12-08 16:40:36199 prerender_url_(url),
[email protected]608c57132011-02-16 14:57:33200 referrer_(referrer),
[email protected]33f74972010-12-08 16:40:36201 profile_(profile),
[email protected]973407b2011-01-26 23:18:23202 page_id_(0),
[email protected]48055042012-07-14 21:12:11203 session_storage_namespace_id_(-1),
[email protected]19440b22011-01-31 18:52:16204 has_stopped_loading_(false),
[email protected]6974ae7e2012-02-16 01:17:59205 has_finished_loading_(false),
[email protected]a3373cd72011-03-16 23:24:31206 final_status_(FINAL_STATUS_MAX),
[email protected]1f259d62012-01-24 23:27:49207 match_complete_status_(MATCH_COMPLETE_DEFAULT),
[email protected]e348af72011-05-23 21:02:49208 prerendering_has_been_cancelled_(false),
[email protected]28a05f3a2011-05-20 15:05:08209 child_id_(-1),
[email protected]86d4ff462011-05-23 17:39:37210 route_id_(-1),
[email protected]e253ab02011-07-07 21:58:39211 origin_(origin),
[email protected]a0358d72012-03-09 14:06:50212 experiment_id_(experiment_id),
213 creator_child_id_(-1) {
[email protected]33f74972010-12-08 16:40:36214 DCHECK(prerender_manager != NULL);
[email protected]8a6e4162011-04-27 19:36:48215}
216
[email protected]26101702012-12-15 21:45:18217PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() {
[email protected]fd4ea84c2012-11-27 20:45:25218 PrerenderContents* new_contents = prerender_manager_->CreatePrerenderContents(
219 prerender_url(), referrer(), origin(), experiment_id());
220
221 new_contents->load_start_time_ = load_start_time_;
222 new_contents->session_storage_namespace_id_ = session_storage_namespace_id_;
223 new_contents->set_match_complete_status(
224 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
225
226 const bool did_init = new_contents->Init();
227 DCHECK(did_init);
228 DCHECK_EQ(alias_urls_.front(), new_contents->alias_urls_.front());
229 DCHECK_EQ(1u, new_contents->alias_urls_.size());
230 new_contents->alias_urls_ = alias_urls_;
231 new_contents->set_match_complete_status(
232 PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
[email protected]26101702012-12-15 21:45:18233 NotifyPrerenderCreatedMatchCompleteReplacement(new_contents);
[email protected]fd4ea84c2012-11-27 20:45:25234 return new_contents;
[email protected]48055042012-07-14 21:12:11235}
236
[email protected]8a6e4162011-04-27 19:36:48237bool PrerenderContents::Init() {
[email protected]2fc4da92011-05-27 16:24:31238 return AddAliasURL(prerender_url_);
[email protected]33f74972010-12-08 16:40:36239}
240
[email protected]5a8dffa2011-01-26 00:40:39241// static
242PrerenderContents::Factory* PrerenderContents::CreateFactory() {
243 return new PrerenderContentsFactoryImpl();
244}
245
[email protected]71b5d242011-04-30 02:27:20246void PrerenderContents::StartPrerendering(
[email protected]2736c032012-05-11 18:06:07247 int creator_child_id,
248 const gfx::Size& size,
[email protected]ac4f4682012-12-08 22:39:26249 SessionStorageNamespace* session_storage_namespace) {
[email protected]71b5d242011-04-30 02:27:20250 DCHECK(profile_ != NULL);
[email protected]2e60e2952012-06-25 17:26:05251 DCHECK(!size.IsEmpty());
[email protected]71b5d242011-04-30 02:27:20252 DCHECK(!prerendering_has_started_);
253 DCHECK(prerender_contents_.get() == NULL);
[email protected]2736c032012-05-11 18:06:07254 DCHECK_EQ(-1, creator_child_id_);
255 DCHECK(size_.IsEmpty());
256 DCHECK_EQ(1U, alias_urls_.size());
[email protected]71b5d242011-04-30 02:27:20257
[email protected]2736c032012-05-11 18:06:07258 creator_child_id_ = creator_child_id;
[email protected]48055042012-07-14 21:12:11259 session_storage_namespace_id_ = session_storage_namespace->id();
[email protected]2736c032012-05-11 18:06:07260 size_ = size;
[email protected]71b5d242011-04-30 02:27:20261
[email protected]48055042012-07-14 21:12:11262 DCHECK(load_start_time_.is_null());
263 load_start_time_ = base::TimeTicks::Now();
264
[email protected]eb9857c2012-05-29 22:50:17265 // Everything after this point sets up the WebContents object and associated
266 // RenderView for the prerender page. Don't do this for members of the
267 // control group.
[email protected]ac4f4682012-12-08 22:39:26268 if (prerender_manager_->IsControlGroup(experiment_id()))
[email protected]eb9857c2012-05-29 22:50:17269 return;
270
[email protected]db6c4ea2013-06-14 17:53:01271 if (origin_ == ORIGIN_LOCAL_PREDICTOR &&
272 IsLocalPredictorPrerenderAlwaysControlEnabled()) {
273 return;
274 }
275
[email protected]eb9857c2012-05-29 22:50:17276 prerendering_has_started_ = true;
277
[email protected]a562aea22012-12-11 22:43:12278 prerender_contents_.reset(CreateWebContents(session_storage_namespace));
[email protected]27e5b3912012-12-16 00:45:37279 BrowserTabContents::AttachTabHelpers(prerender_contents_.get());
[email protected]b97d2a87ce2013-03-01 02:57:59280#if defined(OS_ANDROID)
281 // Delay icon fetching until the contents are getting swapped in
282 // to conserve network usage in mobile devices.
283 FaviconTabHelper::FromWebContents(
284 prerender_contents_.get())->set_should_fetch_icons(false);
285#endif // defined(OS_ANDROID)
[email protected]a562aea22012-12-11 22:43:12286 content::WebContentsObserver::Observe(prerender_contents_.get());
[email protected]2736c032012-05-11 18:06:07287
[email protected]a562aea22012-12-11 22:43:12288 web_contents_delegate_.reset(new WebContentsDelegateImpl(this));
289 prerender_contents_.get()->SetDelegate(web_contents_delegate_.get());
[email protected]0932b30c2012-04-17 13:25:10290 // Set the size of the prerender WebContents.
[email protected]a562aea22012-12-11 22:43:12291 prerender_contents_->GetView()->SizeContents(size_);
[email protected]208ce7e2011-08-27 04:35:13292
[email protected]5ee38b882011-05-05 00:18:57293 // Register as an observer of the RenderViewHost so we get messages.
294 render_view_host_observer_.reset(
[email protected]cfd820d2012-04-29 16:29:07295 new PrerenderRenderViewHostObserver(this, GetRenderViewHostMutable()));
[email protected]5ee38b882011-05-05 00:18:57296
[email protected]cfd820d2012-04-29 16:29:07297 child_id_ = GetRenderViewHost()->GetProcess()->GetID();
298 route_id_ = GetRenderViewHost()->GetRoutingID();
[email protected]ac1f70b2011-05-03 00:46:05299
[email protected]71b5d242011-04-30 02:27:20300 // Register this with the ResourceDispatcherHost as a prerender
301 // RenderViewHost. This must be done before the Navigate message to catch all
302 // resource requests, but as it is on the same thread as the Navigate message
303 // (IO) there is no race condition.
[email protected]ac4f4682012-12-08 22:39:26304 AddObserver(prerender_manager()->prerender_tracker());
305 NotifyPrerenderStart();
[email protected]ac1f70b2011-05-03 00:46:05306
307 // Close ourselves when the application is shutting down.
[email protected]966c9a42012-09-25 14:40:21308 notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
[email protected]ad50def52011-10-19 23:17:07309 content::NotificationService::AllSources());
[email protected]ac1f70b2011-05-03 00:46:05310
311 // Register for our parent profile to shutdown, so we can shut ourselves down
312 // as well (should only be called for OTR profiles, as we should receive
313 // APP_TERMINATING before non-OTR profiles are destroyed).
314 // TODO(tburkard): figure out if this is needed.
[email protected]432115822011-07-10 15:52:27315 notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
[email protected]6c2381d2011-10-19 02:52:53316 content::Source<Profile>(profile_));
[email protected]ac1f70b2011-05-03 00:46:05317
[email protected]165602b2011-05-05 14:46:52318 // Register to inform new RenderViews that we're prerendering.
319 notification_registrar_.Add(
[email protected]d53a08c2012-07-18 20:35:30320 this, content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
[email protected]a562aea22012-12-11 22:43:12321 content::Source<WebContents>(prerender_contents_.get()));
[email protected]165602b2011-05-05 14:46:52322
[email protected]ac1f70b2011-05-03 00:46:05323 // Register for redirect notifications sourced from |this|.
[email protected]225e7432011-05-03 02:16:11324 notification_registrar_.Add(
[email protected]432115822011-07-10 15:52:27325 this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
[email protected]a562aea22012-12-11 22:43:12326 content::Source<WebContents>(prerender_contents_.get()));
[email protected]71b5d242011-04-30 02:27:20327
[email protected]bf70edce2012-06-20 22:32:22328 // Transfer over the user agent override.
[email protected]a562aea22012-12-11 22:43:12329 prerender_contents_.get()->SetUserAgentOverride(
[email protected]bf70edce2012-06-20 22:32:22330 prerender_manager_->config().user_agent_override);
331
[email protected]cf002332012-08-14 19:17:47332 content::NavigationController::LoadURLParams load_url_params(
333 prerender_url_);
334 load_url_params.referrer = referrer_;
335 load_url_params.transition_type = (origin_ == ORIGIN_OMNIBOX ?
336 content::PAGE_TRANSITION_TYPED : content::PAGE_TRANSITION_LINK);
337 load_url_params.override_user_agent =
338 prerender_manager_->config().is_overriding_user_agent ?
339 content::NavigationController::UA_OVERRIDE_TRUE :
340 content::NavigationController::UA_OVERRIDE_FALSE;
[email protected]a562aea22012-12-11 22:43:12341 prerender_contents_.get()->GetController().LoadURLWithParams(load_url_params);
[email protected]71b5d242011-04-30 02:27:20342}
343
[email protected]55e98aa2011-03-23 17:10:32344bool PrerenderContents::GetChildId(int* child_id) const {
345 CHECK(child_id);
[email protected]28a05f3a2011-05-20 15:05:08346 DCHECK_GE(child_id_, -1);
347 *child_id = child_id_;
348 return child_id_ != -1;
[email protected]55e98aa2011-03-23 17:10:32349}
350
351bool PrerenderContents::GetRouteId(int* route_id) const {
352 CHECK(route_id);
[email protected]28a05f3a2011-05-20 15:05:08353 DCHECK_GE(route_id_, -1);
354 *route_id = route_id_;
355 return route_id_ != -1;
[email protected]55e98aa2011-03-23 17:10:32356}
357
[email protected]ac4f4682012-12-08 22:39:26358void PrerenderContents::SetFinalStatus(FinalStatus final_status) {
[email protected]19440b22011-01-31 18:52:16359 DCHECK(final_status >= FINAL_STATUS_USED && final_status < FINAL_STATUS_MAX);
[email protected]1f259d62012-01-24 23:27:49360 DCHECK(final_status_ == FINAL_STATUS_MAX);
[email protected]ec17231bb2011-02-16 20:06:09361
[email protected]19440b22011-01-31 18:52:16362 final_status_ = final_status;
363}
364
[email protected]33f74972010-12-08 16:40:36365PrerenderContents::~PrerenderContents() {
[email protected]ac4f4682012-12-08 22:39:26366 DCHECK_NE(FINAL_STATUS_MAX, final_status());
367 DCHECK(
368 prerendering_has_been_cancelled() || final_status() == FINAL_STATUS_USED);
369 DCHECK_NE(ORIGIN_MAX, origin());
[email protected]36492a32011-03-30 16:39:10370
[email protected]1f259d62012-01-24 23:27:49371 prerender_manager_->RecordFinalStatusWithMatchCompleteStatus(
[email protected]ac4f4682012-12-08 22:39:26372 origin(), experiment_id(), match_complete_status(), final_status());
[email protected]19440b22011-01-31 18:52:16373
[email protected]f5b9c1b522013-05-15 09:50:10374 // Broadcast the removal of aliases.
375 for (content::RenderProcessHost::iterator host_iterator =
376 content::RenderProcessHost::AllHostsIterator();
377 !host_iterator.IsAtEnd();
378 host_iterator.Advance()) {
379 content::RenderProcessHost* host = host_iterator.GetCurrentValue();
380 host->Send(new PrerenderMsg_OnPrerenderRemoveAliases(alias_urls_));
381 }
382
[email protected]0932b30c2012-04-17 13:25:10383 // If we still have a WebContents, clean up anything we need to and then
[email protected]d3c79f392011-05-20 20:04:56384 // destroy it.
385 if (prerender_contents_.get())
386 delete ReleasePrerenderContents();
[email protected]33f74972010-12-08 16:40:36387}
388
[email protected]ac4f4682012-12-08 22:39:26389void PrerenderContents::AddObserver(Observer* observer) {
390 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
391 observer_list_.AddObserver(observer);
392}
393
[email protected]26101702012-12-15 21:45:18394void PrerenderContents::RemoveObserver(Observer* observer) {
395 observer_list_.RemoveObserver(observer);
396}
397
[email protected]432115822011-07-10 15:52:27398void PrerenderContents::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:53399 const content::NotificationSource& source,
400 const content::NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:27401 switch (type) {
402 case chrome::NOTIFICATION_PROFILE_DESTROYED:
[email protected]19440b22011-01-31 18:52:16403 Destroy(FINAL_STATUS_PROFILE_DESTROYED);
404 return;
[email protected]ec17231bb2011-02-16 20:06:09405
[email protected]966c9a42012-09-25 14:40:21406 case chrome::NOTIFICATION_APP_TERMINATING:
[email protected]19440b22011-01-31 18:52:16407 Destroy(FINAL_STATUS_APP_TERMINATING);
408 return;
[email protected]549e89a2011-02-04 18:02:31409
[email protected]432115822011-07-10 15:52:27410 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
[email protected]88de7c352011-04-13 12:33:31411 // RESOURCE_RECEIVED_REDIRECT can come for any resource on a page.
412 // If it's a redirect on the top-level resource, the name needs
413 // to be remembered for future matching, and if it redirects to
414 // an https resource, it needs to be canceled. If a subresource
415 // is redirected, nothing changes.
[email protected]a562aea22012-12-11 22:43:12416 DCHECK_EQ(content::Source<WebContents>(source).ptr(),
417 prerender_contents_.get());
[email protected]88de7c352011-04-13 12:33:31418 ResourceRedirectDetails* resource_redirect_details =
[email protected]6c2381d2011-10-19 02:52:53419 content::Details<ResourceRedirectDetails>(details).ptr();
[email protected]88de7c352011-04-13 12:33:31420 CHECK(resource_redirect_details);
[email protected]48227592012-03-19 13:13:44421 if (resource_redirect_details->resource_type ==
[email protected]88de7c352011-04-13 12:33:31422 ResourceType::MAIN_FRAME) {
[email protected]48227592012-03-19 13:13:44423 if (!AddAliasURL(resource_redirect_details->new_url))
[email protected]8a6e4162011-04-27 19:36:48424 return;
[email protected]88de7c352011-04-13 12:33:31425 }
426 break;
427 }
428
[email protected]d53a08c2012-07-18 20:35:30429 case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
[email protected]165602b2011-05-05 14:46:52430 if (prerender_contents_.get()) {
[email protected]fbc5e5f92012-01-02 06:08:32431 DCHECK_EQ(content::Source<WebContents>(source).ptr(),
[email protected]a562aea22012-12-11 22:43:12432 prerender_contents_.get());
[email protected]165602b2011-05-05 14:46:52433
[email protected]6c2381d2011-10-19 02:52:53434 content::Details<RenderViewHost> new_render_view_host(details);
[email protected]b54c6c62011-05-12 15:04:04435 OnRenderViewHostCreated(new_render_view_host.ptr());
436
[email protected]0932b30c2012-04-17 13:25:10437 // When a new RenderView is created for a prerendering WebContents,
[email protected]b54c6c62011-05-12 15:04:04438 // tell the new RenderView it's being used for prerendering before any
439 // navigations occur. Note that this is always triggered before the
440 // first navigation, so there's no need to send the message just after
[email protected]0932b30c2012-04-17 13:25:10441 // the WebContents is created.
[email protected]165602b2011-05-05 14:46:52442 new_render_view_host->Send(
[email protected]a0358d72012-03-09 14:06:50443 new PrerenderMsg_SetIsPrerendering(
[email protected]9f76c1e2012-03-05 15:15:58444 new_render_view_host->GetRoutingID(),
[email protected]2ccf45c2011-08-19 23:35:50445 true));
[email protected]329c7252011-06-29 19:43:05446
[email protected]5725b2e2011-09-01 13:11:27447 // Make sure the size of the RenderViewHost has been passed to the new
448 // RenderView. Otherwise, the size may not be sent until the
449 // RenderViewReady event makes it from the render process to the UI
450 // thread of the browser process. When the RenderView receives its
451 // size, is also sets itself to be visible, which would then break the
452 // visibility API.
453 new_render_view_host->WasResized();
[email protected]a562aea22012-12-11 22:43:12454 prerender_contents_->WasHidden();
[email protected]208ce7e2011-08-27 04:35:13455 }
[email protected]5725b2e2011-09-01 13:11:27456 break;
[email protected]208ce7e2011-08-27 04:35:13457 }
458
[email protected]33f74972010-12-08 16:40:36459 default:
460 NOTREACHED() << "Unexpected notification sent.";
461 break;
462 }
463}
464
[email protected]b54c6c62011-05-12 15:04:04465void PrerenderContents::OnRenderViewHostCreated(
466 RenderViewHost* new_render_view_host) {
467}
468
[email protected]ba17cdb2012-11-30 02:12:04469size_t PrerenderContents::pending_prerender_count() const {
470 return pending_prerenders_.size();
471}
472
[email protected]de1fcdd2012-04-06 23:01:07473WebContents* PrerenderContents::CreateWebContents(
[email protected]48055042012-07-14 21:12:11474 SessionStorageNamespace* session_storage_namespace) {
[email protected]d1198fd2012-08-13 22:50:19475 // TODO(ajwong): Remove the temporary map once prerendering is aware of
476 // multiple session storage namespaces per tab.
477 content::SessionStorageNamespaceMap session_storage_namespace_map;
[email protected]007b3f82013-04-09 08:46:45478 session_storage_namespace_map[std::string()] = session_storage_namespace;
479 return WebContents::CreateWithSessionStorage(
[email protected]54944cde2012-12-09 09:24:59480 WebContents::CreateParams(profile_), session_storage_namespace_map);
[email protected]de1fcdd2012-04-06 23:01:07481}
482
[email protected]ac4f4682012-12-08 22:39:26483void PrerenderContents::NotifyPrerenderStart() {
484 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
485 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStart(this));
486}
487
[email protected]49fc07b2013-01-03 21:05:22488void PrerenderContents::NotifyPrerenderStopLoading() {
489 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStopLoading(this));
490}
491
[email protected]ac4f4682012-12-08 22:39:26492void PrerenderContents::NotifyPrerenderStop() {
493 DCHECK_NE(FINAL_STATUS_MAX, final_status_);
494 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStop(this));
495 observer_list_.Clear();
496}
497
[email protected]26101702012-12-15 21:45:18498void PrerenderContents::NotifyPrerenderCreatedMatchCompleteReplacement(
499 PrerenderContents* replacement) {
500 FOR_EACH_OBSERVER(Observer, observer_list_,
501 OnPrerenderCreatedMatchCompleteReplacement(this,
502 replacement));
503}
504
[email protected]795c28972012-12-06 06:13:39505void PrerenderContents::DidUpdateFaviconURL(
[email protected]60f36f92011-04-12 16:18:31506 int32 page_id,
[email protected]795c28972012-12-06 06:13:39507 const std::vector<content::FaviconURL>& urls) {
[email protected]b99b13b2011-05-04 20:59:04508 VLOG(1) << "PrerenderContents::OnUpdateFaviconURL" << icon_url_;
[email protected]795c28972012-12-06 06:13:39509 for (std::vector<content::FaviconURL>::const_iterator it = urls.begin();
[email protected]8fdb6f32011-04-26 15:22:59510 it != urls.end(); ++it) {
[email protected]795c28972012-12-06 06:13:39511 if (it->icon_type == content::FaviconURL::FAVICON) {
[email protected]8fdb6f32011-04-26 15:22:59512 icon_url_ = it->icon_url;
[email protected]b99b13b2011-05-04 20:59:04513 VLOG(1) << icon_url_;
[email protected]60f36f92011-04-12 16:18:31514 return;
515 }
516 }
[email protected]c775fc8c2011-02-08 23:07:15517}
518
[email protected]d085f5c2011-02-20 12:17:47519bool PrerenderContents::AddAliasURL(const GURL& url) {
[email protected]f9034cf2011-07-21 12:43:41520 const bool http = url.SchemeIs(chrome::kHttpScheme);
521 const bool https = url.SchemeIs(chrome::kHttpsScheme);
[email protected]75d90c12013-03-20 19:50:16522 if (!http && !https) {
[email protected]027dc6c42012-06-14 19:34:20523 DCHECK_NE(MATCH_COMPLETE_REPLACEMENT_PENDING, match_complete_status_);
[email protected]f9034cf2011-07-21 12:43:41524 Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
525 return false;
526 }
527 if (https && !prerender_manager_->config().https_allowed) {
[email protected]027dc6c42012-06-14 19:34:20528 DCHECK_NE(MATCH_COMPLETE_REPLACEMENT_PENDING, match_complete_status_);
[email protected]f9034cf2011-07-21 12:43:41529 Destroy(FINAL_STATUS_HTTPS);
[email protected]d085f5c2011-02-20 12:17:47530 return false;
[email protected]8a6e4162011-04-27 19:36:48531 }
[email protected]027dc6c42012-06-14 19:34:20532 if (match_complete_status_ != MATCH_COMPLETE_REPLACEMENT_PENDING &&
[email protected]3a6ec762012-10-17 16:01:01533 prerender_manager_->HasRecentlyBeenNavigatedTo(origin(), url)) {
[email protected]84b5da92011-05-19 17:53:56534 Destroy(FINAL_STATUS_RECENTLY_VISITED);
535 return false;
536 }
[email protected]f9034cf2011-07-21 12:43:41537
[email protected]f39506a82011-01-18 23:46:38538 alias_urls_.push_back(url);
[email protected]f5b9c1b522013-05-15 09:50:10539
540 for (content::RenderProcessHost::iterator host_iterator =
541 content::RenderProcessHost::AllHostsIterator();
542 !host_iterator.IsAtEnd();
543 host_iterator.Advance()) {
544 content::RenderProcessHost* host = host_iterator.GetCurrentValue();
545 host->Send(new PrerenderMsg_OnPrerenderAddAlias(url));
546 }
547
[email protected]d085f5c2011-02-20 12:17:47548 return true;
[email protected]f39506a82011-01-18 23:46:38549}
550
[email protected]48055042012-07-14 21:12:11551bool PrerenderContents::Matches(
552 const GURL& url,
553 const SessionStorageNamespace* session_storage_namespace) const {
[email protected]48055042012-07-14 21:12:11554 if (session_storage_namespace &&
[email protected]75d90c12013-03-20 19:50:16555 session_storage_namespace_id_ != session_storage_namespace->id()) {
[email protected]48055042012-07-14 21:12:11556 return false;
[email protected]75d90c12013-03-20 19:50:16557 }
[email protected]48055042012-07-14 21:12:11558 return std::count_if(alias_urls_.begin(), alias_urls_.end(),
559 std::bind2nd(std::equal_to<GURL>(), url)) != 0;
[email protected]f39506a82011-01-18 23:46:38560}
[email protected]973407b2011-01-26 23:18:23561
[email protected]9cddb1a22011-11-15 15:04:27562void PrerenderContents::RenderViewGone(base::TerminationStatus status) {
[email protected]5ee38b882011-05-05 00:18:57563 Destroy(FINAL_STATUS_RENDERER_CRASHED);
564}
565
[email protected]89793072012-07-23 22:25:29566void PrerenderContents::DidStopLoading(
567 content::RenderViewHost* render_view_host) {
[email protected]973407b2011-01-26 23:18:23568 has_stopped_loading_ = true;
[email protected]49fc07b2013-01-03 21:05:22569 NotifyPrerenderStopLoading();
[email protected]973407b2011-01-26 23:18:23570}
[email protected]19440b22011-01-31 18:52:16571
[email protected]5f5b9e4cf2011-09-07 21:26:05572void PrerenderContents::DidStartProvisionalLoadForFrame(
573 int64 frame_id,
[email protected]d37c33e2012-10-12 13:35:13574 int64 parent_frame_id,
[email protected]5f5b9e4cf2011-09-07 21:26:05575 bool is_main_frame,
576 const GURL& validated_url,
577 bool is_error_page,
[email protected]ead9009e2013-01-07 22:06:32578 bool is_iframe_srcdoc,
[email protected]5f5b9e4cf2011-09-07 21:26:05579 RenderViewHost* render_view_host) {
580 if (is_main_frame) {
581 if (!AddAliasURL(validated_url))
582 return;
583
584 // Usually, this event fires if the user clicks or enters a new URL.
585 // Neither of these can happen in the case of an invisible prerender.
586 // So the cause is: Some JavaScript caused a new URL to be loaded. In that
587 // case, the spinner would start again in the browser, so we must reset
588 // has_stopped_loading_ so that the spinner won't be stopped.
589 has_stopped_loading_ = false;
[email protected]6974ae7e2012-02-16 01:17:59590 has_finished_loading_ = false;
[email protected]5f5b9e4cf2011-09-07 21:26:05591 }
592}
593
[email protected]6974ae7e2012-02-16 01:17:59594void PrerenderContents::DidFinishLoad(int64 frame_id,
595 const GURL& validated_url,
[email protected]7bb761892012-07-20 09:32:47596 bool is_main_frame,
597 RenderViewHost* render_view_host) {
[email protected]6974ae7e2012-02-16 01:17:59598 if (is_main_frame)
599 has_finished_loading_ = true;
600}
601
[email protected]19440b22011-01-31 18:52:16602void PrerenderContents::Destroy(FinalStatus final_status) {
[email protected]26101702012-12-15 21:45:18603 DCHECK_NE(final_status, FINAL_STATUS_USED);
604
[email protected]e348af72011-05-23 21:02:49605 if (prerendering_has_been_cancelled_)
[email protected]5ee38b882011-05-05 00:18:57606 return;
[email protected]4c154ff82011-02-15 11:23:59607
[email protected]28a05f3a2011-05-20 15:05:08608 if (child_id_ != -1 && route_id_ != -1) {
609 // Cancel the prerender in the PrerenderTracker. This is needed
610 // because destroy may be called directly from the UI thread without calling
611 // TryCancel(). This is difficult to completely avoid, since prerendering
612 // can be cancelled before a RenderView is created.
[email protected]ac4f4682012-12-08 22:39:26613 bool is_cancelled = prerender_manager()->prerender_tracker()->TryCancel(
[email protected]1459fb62011-05-25 19:03:27614 child_id_, route_id_, final_status);
[email protected]28a05f3a2011-05-20 15:05:08615 CHECK(is_cancelled);
616
617 // A different final status may have been set already from another thread.
618 // If so, use it instead.
[email protected]ac4f4682012-12-08 22:39:26619 if (!prerender_manager()->prerender_tracker()->
620 GetFinalStatus(child_id_, route_id_, &final_status)) {
[email protected]28a05f3a2011-05-20 15:05:08621 NOTREACHED();
622 }
623 }
[email protected]ac4f4682012-12-08 22:39:26624 SetFinalStatus(final_status);
[email protected]e348af72011-05-23 21:02:49625
[email protected]49308e282011-08-11 00:17:40626 prerendering_has_been_cancelled_ = true;
[email protected]128c74062012-11-27 17:55:53627 prerender_manager_->AddToHistory(this);
[email protected]447f9ab2011-11-14 23:56:35628 prerender_manager_->MoveEntryToPendingDelete(this, final_status);
[email protected]49308e282011-08-11 00:17:40629
[email protected]26101702012-12-15 21:45:18630 if (!prerender_manager_->IsControlGroup(experiment_id()) &&
631 (prerendering_has_started() ||
632 match_complete_status() == MATCH_COMPLETE_REPLACEMENT)) {
633 NotifyPrerenderStop();
634 }
635
[email protected]5ee38b882011-05-05 00:18:57636 // We may destroy the PrerenderContents before we have initialized the
637 // RenderViewHost. Otherwise set the Observer's PrerenderContents to NULL to
638 // avoid any more messages being sent.
[email protected]128c74062012-11-27 17:55:53639 if (render_view_host_observer_)
[email protected]5ee38b882011-05-05 00:18:57640 render_view_host_observer_->set_prerender_contents(NULL);
[email protected]ba9f8fb2011-02-24 20:19:26641}
642
[email protected]ba9f8fb2011-02-24 20:19:26643base::ProcessMetrics* PrerenderContents::MaybeGetProcessMetrics() {
644 if (process_metrics_.get() == NULL) {
[email protected]bd6b9242011-04-04 18:38:31645 // If a PrenderContents hasn't started prerending, don't be fully formed.
[email protected]cfd820d2012-04-29 16:29:07646 if (!GetRenderViewHost() || !GetRenderViewHost()->GetProcess())
[email protected]bd6b9242011-04-04 18:38:31647 return NULL;
[email protected]cfd820d2012-04-29 16:29:07648 base::ProcessHandle handle = GetRenderViewHost()->GetProcess()->GetHandle();
[email protected]ba9f8fb2011-02-24 20:19:26649 if (handle == base::kNullProcessHandle)
650 return NULL;
651#if !defined(OS_MACOSX)
652 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
653#else
654 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(
655 handle,
[email protected]458433c2012-02-29 23:43:39656 content::BrowserChildProcessHost::GetPortProvider()));
[email protected]ba9f8fb2011-02-24 20:19:26657#endif
658 }
659
660 return process_metrics_.get();
661}
662
663void PrerenderContents::DestroyWhenUsingTooManyResources() {
664 base::ProcessMetrics* metrics = MaybeGetProcessMetrics();
665 if (metrics == NULL)
666 return;
667
668 size_t private_bytes, shared_bytes;
[email protected]940da332011-06-30 18:09:11669 if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes) &&
670 private_bytes > prerender_manager_->config().max_bytes) {
[email protected]75d90c12013-03-20 19:50:16671 Destroy(FINAL_STATUS_MEMORY_LIMIT_EXCEEDED);
[email protected]ba9f8fb2011-02-24 20:19:26672 }
673}
674
[email protected]a562aea22012-12-11 22:43:12675WebContents* PrerenderContents::ReleasePrerenderContents() {
676 prerender_contents_->SetDelegate(NULL);
[email protected]5ee38b882011-05-05 00:18:57677 render_view_host_observer_.reset();
[email protected]d8c660432011-12-22 20:51:25678 content::WebContentsObserver::Observe(NULL);
[email protected]71b5d242011-04-30 02:27:20679 return prerender_contents_.release();
680}
681
[email protected]cfd820d2012-04-29 16:29:07682RenderViewHost* PrerenderContents::GetRenderViewHostMutable() {
683 return const_cast<RenderViewHost*>(GetRenderViewHost());
[email protected]5ee38b882011-05-05 00:18:57684}
685
[email protected]cfd820d2012-04-29 16:29:07686const RenderViewHost* PrerenderContents::GetRenderViewHost() const {
[email protected]2fc4da92011-05-27 16:24:31687 if (!prerender_contents_.get())
688 return NULL;
[email protected]a562aea22012-12-11 22:43:12689 return prerender_contents_->GetRenderViewHost();
[email protected]225e7432011-05-03 02:16:11690}
691
[email protected]853493a2012-09-26 02:49:42692void PrerenderContents::DidNavigate(
693 const history::HistoryAddPageArgs& add_page_args) {
694 add_page_vector_.push_back(add_page_args);
695}
696
[email protected]a562aea22012-12-11 22:43:12697void PrerenderContents::CommitHistory(WebContents* tab) {
698 HistoryTabHelper* history_tab_helper = HistoryTabHelper::FromWebContents(tab);
[email protected]853493a2012-09-26 02:49:42699 for (size_t i = 0; i < add_page_vector_.size(); ++i)
[email protected]3cbe7212012-09-28 17:02:31700 history_tab_helper->UpdateHistoryForNavigation(add_page_vector_[i]);
[email protected]d3961e82011-05-20 06:32:03701}
702
[email protected]e2602042011-06-15 19:57:29703Value* PrerenderContents::GetAsValue() const {
704 if (!prerender_contents_.get())
705 return NULL;
706 DictionaryValue* dict_value = new DictionaryValue();
707 dict_value->SetString("url", prerender_url_.spec());
708 base::TimeTicks current_time = base::TimeTicks::Now();
709 base::TimeDelta duration = current_time - load_start_time_;
710 dict_value->SetInteger("duration", duration.InSeconds());
[email protected]55615c62013-05-31 16:45:07711 dict_value->SetBoolean("is_loaded", prerender_contents_ &&
712 !prerender_contents_->IsLoading());
[email protected]e2602042011-06-15 19:57:29713 return dict_value;
714}
715
[email protected]9e1ad4b2011-08-14 16:49:19716bool PrerenderContents::IsCrossSiteNavigationPending() const {
[email protected]a562aea22012-12-11 22:43:12717 if (!prerender_contents_)
[email protected]9e1ad4b2011-08-14 16:49:19718 return false;
[email protected]a562aea22012-12-11 22:43:12719 return (prerender_contents_->GetSiteInstance() !=
720 prerender_contents_->GetPendingSiteInstance());
[email protected]9e1ad4b2011-08-14 16:49:19721}
722
723
[email protected]4c154ff82011-02-15 11:23:59724} // namespace prerender