Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_contents.cc
blob67e7d101f120401cebecb413464fa3d9e06e0f86
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.
5 #include "chrome/browser/prerender/prerender_contents.h"
7 #include <algorithm>
8 #include <functional>
9 #include <utility>
11 #include "base/bind.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/history/history_tab_helper.h"
15 #include "chrome/browser/prerender/prerender_field_trial.h"
16 #include "chrome/browser/prerender/prerender_final_status.h"
17 #include "chrome/browser/prerender/prerender_handle.h"
18 #include "chrome/browser/prerender/prerender_manager.h"
19 #include "chrome/browser/prerender/prerender_manager_factory.h"
20 #include "chrome/browser/prerender/prerender_resource_throttle.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/task_management/web_contents_tags.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/tab_helpers.h"
25 #include "chrome/browser/ui/web_contents_sizer.h"
26 #include "chrome/common/prerender_messages.h"
27 #include "chrome/common/render_messages.h"
28 #include "chrome/common/url_constants.h"
29 #include "components/history/core/browser/history_types.h"
30 #include "content/public/browser/browser_child_process_host.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/render_frame_host.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/resource_request_details.h"
37 #include "content/public/browser/session_storage_namespace.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_delegate.h"
40 #include "content/public/common/frame_navigate_params.h"
41 #include "ui/base/page_transition_types.h"
42 #include "ui/gfx/geometry/rect.h"
44 using content::BrowserThread;
45 using content::DownloadItem;
46 using content::OpenURLParams;
47 using content::RenderViewHost;
48 using content::ResourceRedirectDetails;
49 using content::ResourceType;
50 using content::SessionStorageNamespace;
51 using content::WebContents;
53 namespace prerender {
55 namespace {
57 void ResumeThrottles(
58 std::vector<base::WeakPtr<PrerenderResourceThrottle> > throttles) {
59 for (size_t i = 0; i < throttles.size(); i++) {
60 if (throttles[i])
61 throttles[i]->Resume();
65 } // namespace
67 class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
68 public:
69 PrerenderContents* CreatePrerenderContents(
70 PrerenderManager* prerender_manager,
71 Profile* profile,
72 const GURL& url,
73 const content::Referrer& referrer,
74 Origin origin) override {
75 return new PrerenderContents(prerender_manager, profile, url, referrer,
76 origin);
80 // WebContentsDelegateImpl -----------------------------------------------------
82 class PrerenderContents::WebContentsDelegateImpl
83 : public content::WebContentsDelegate {
84 public:
85 explicit WebContentsDelegateImpl(PrerenderContents* prerender_contents)
86 : prerender_contents_(prerender_contents) {
89 // content::WebContentsDelegate implementation:
90 WebContents* OpenURLFromTab(WebContents* source,
91 const OpenURLParams& params) override {
92 // |OpenURLFromTab| is typically called when a frame performs a navigation
93 // that requires the browser to perform the transition instead of WebKit.
94 // Examples include prerendering a site that redirects to an app URL, or if
95 // --site-per-process is specified and the prerendered frame redirects to a
96 // different origin.
97 // TODO(cbentzel): Consider supporting this for CURRENT_TAB dispositions, if
98 // it is a common case during prerenders.
99 prerender_contents_->Destroy(FINAL_STATUS_OPEN_URL);
100 return NULL;
103 void CloseContents(content::WebContents* contents) override {
104 prerender_contents_->Destroy(FINAL_STATUS_CLOSED);
107 void CanDownload(const GURL& url,
108 const std::string& request_method,
109 const base::Callback<void(bool)>& callback) override {
110 prerender_contents_->Destroy(FINAL_STATUS_DOWNLOAD);
111 // Cancel the download.
112 callback.Run(false);
115 bool ShouldCreateWebContents(
116 WebContents* web_contents,
117 int route_id,
118 int main_frame_route_id,
119 WindowContainerType window_container_type,
120 const std::string& frame_name,
121 const GURL& target_url,
122 const std::string& partition_id,
123 SessionStorageNamespace* session_storage_namespace) override {
124 // Since we don't want to permit child windows that would have a
125 // window.opener property, terminate prerendering.
126 prerender_contents_->Destroy(FINAL_STATUS_CREATE_NEW_WINDOW);
127 // Cancel the popup.
128 return false;
131 bool OnGoToEntryOffset(int offset) override {
132 // This isn't allowed because the history merge operation
133 // does not work if there are renderer issued challenges.
134 // TODO(cbentzel): Cancel in this case? May not need to do
135 // since render-issued offset navigations are not guaranteed,
136 // but indicates that the page cares about the history.
137 return false;
140 bool ShouldSuppressDialogs(WebContents* source) override {
141 // We still want to show the user the message when they navigate to this
142 // page, so cancel this prerender.
143 prerender_contents_->Destroy(FINAL_STATUS_JAVASCRIPT_ALERT);
144 // Always suppress JavaScript messages if they're triggered by a page being
145 // prerendered.
146 return true;
149 void RegisterProtocolHandler(WebContents* web_contents,
150 const std::string& protocol,
151 const GURL& url,
152 bool user_gesture) override {
153 // TODO(mmenke): Consider supporting this if it is a common case during
154 // prerenders.
155 prerender_contents_->Destroy(FINAL_STATUS_REGISTER_PROTOCOL_HANDLER);
158 gfx::Size GetSizeForNewRenderView(WebContents* web_contents) const override {
159 // Have to set the size of the RenderView on initialization to be sure it is
160 // set before the RenderView is hidden on all platforms (esp. Android).
161 return prerender_contents_->size_;
164 private:
165 PrerenderContents* prerender_contents_;
168 void PrerenderContents::Observer::OnPrerenderStopLoading(
169 PrerenderContents* contents) {
172 void PrerenderContents::Observer::OnPrerenderDomContentLoaded(
173 PrerenderContents* contents) {
176 void PrerenderContents::Observer::OnPrerenderCreatedMatchCompleteReplacement(
177 PrerenderContents* contents, PrerenderContents* replacement) {
180 PrerenderContents::Observer::Observer() {
183 PrerenderContents::Observer::~Observer() {
186 PrerenderContents::PrerenderContents(
187 PrerenderManager* prerender_manager,
188 Profile* profile,
189 const GURL& url,
190 const content::Referrer& referrer,
191 Origin origin)
192 : prerendering_has_started_(false),
193 session_storage_namespace_id_(-1),
194 prerender_manager_(prerender_manager),
195 prerender_url_(url),
196 referrer_(referrer),
197 profile_(profile),
198 has_stopped_loading_(false),
199 has_finished_loading_(false),
200 final_status_(FINAL_STATUS_MAX),
201 match_complete_status_(MATCH_COMPLETE_DEFAULT),
202 prerendering_has_been_cancelled_(false),
203 child_id_(-1),
204 route_id_(-1),
205 origin_(origin),
206 network_bytes_(0) {
207 DCHECK(prerender_manager != NULL);
210 PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() {
211 PrerenderContents* new_contents = prerender_manager_->CreatePrerenderContents(
212 prerender_url(), referrer(), origin());
214 new_contents->load_start_time_ = load_start_time_;
215 new_contents->session_storage_namespace_id_ = session_storage_namespace_id_;
216 new_contents->set_match_complete_status(
217 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
219 const bool did_init = new_contents->Init();
220 DCHECK(did_init);
221 DCHECK_EQ(alias_urls_.front(), new_contents->alias_urls_.front());
222 DCHECK_EQ(1u, new_contents->alias_urls_.size());
223 new_contents->alias_urls_ = alias_urls_;
224 // Erase all but the first alias URL; the replacement has adopted the
225 // remainder without increasing the renderer-side reference count.
226 alias_urls_.resize(1);
227 new_contents->set_match_complete_status(
228 PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
229 NotifyPrerenderCreatedMatchCompleteReplacement(new_contents);
230 return new_contents;
233 bool PrerenderContents::Init() {
234 return AddAliasURL(prerender_url_);
237 // static
238 PrerenderContents::Factory* PrerenderContents::CreateFactory() {
239 return new PrerenderContentsFactoryImpl();
242 // static
243 PrerenderContents* PrerenderContents::FromWebContents(
244 content::WebContents* web_contents) {
245 if (!web_contents)
246 return NULL;
247 PrerenderManager* prerender_manager = PrerenderManagerFactory::GetForProfile(
248 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
249 if (!prerender_manager)
250 return NULL;
251 return prerender_manager->GetPrerenderContents(web_contents);
254 void PrerenderContents::StartPrerendering(
255 const gfx::Size& size,
256 SessionStorageNamespace* session_storage_namespace) {
257 DCHECK(profile_ != NULL);
258 DCHECK(!size.IsEmpty());
259 DCHECK(!prerendering_has_started_);
260 DCHECK(prerender_contents_.get() == NULL);
261 DCHECK(size_.IsEmpty());
262 DCHECK_EQ(1U, alias_urls_.size());
264 session_storage_namespace_id_ = session_storage_namespace->id();
265 size_ = size;
267 DCHECK(load_start_time_.is_null());
268 load_start_time_ = base::TimeTicks::Now();
270 // Everything after this point sets up the WebContents object and associated
271 // RenderView for the prerender page. Don't do this for members of the
272 // control group.
273 if (prerender_manager_->IsControlGroup())
274 return;
276 prerendering_has_started_ = true;
278 prerender_contents_.reset(CreateWebContents(session_storage_namespace));
279 TabHelpers::AttachTabHelpers(prerender_contents_.get());
280 content::WebContentsObserver::Observe(prerender_contents_.get());
282 // Tag the prerender contents with the task manager specific prerender tag, so
283 // that it shows up in the task manager.
284 task_management::WebContentsTags::CreateForPrerenderContents(
285 prerender_contents_.get());
287 web_contents_delegate_.reset(new WebContentsDelegateImpl(this));
288 prerender_contents_.get()->SetDelegate(web_contents_delegate_.get());
289 // Set the size of the prerender WebContents.
290 ResizeWebContents(prerender_contents_.get(), size_);
292 // TODO(davidben): This logic assumes each prerender has at most one
293 // route. https://crbug.com/440544
294 child_id_ = GetRenderViewHost()->GetProcess()->GetID();
295 route_id_ = GetRenderViewHost()->GetRoutingID();
297 // TODO(davidben): This logic assumes each prerender has at most one
298 // process. https://crbug.com/440544
299 prerender_manager()->AddPrerenderProcessHost(
300 GetRenderViewHost()->GetProcess());
302 NotifyPrerenderStart();
304 // Close ourselves when the application is shutting down.
305 notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
306 content::NotificationService::AllSources());
308 // Register to inform new RenderViews that we're prerendering.
309 notification_registrar_.Add(
310 this, content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
311 content::Source<WebContents>(prerender_contents_.get()));
313 // Transfer over the user agent override.
314 prerender_contents_.get()->SetUserAgentOverride(
315 prerender_manager_->config().user_agent_override);
317 content::NavigationController::LoadURLParams load_url_params(
318 prerender_url_);
319 load_url_params.referrer = referrer_;
320 load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
321 if (origin_ == ORIGIN_OMNIBOX) {
322 load_url_params.transition_type = ui::PageTransitionFromInt(
323 ui::PAGE_TRANSITION_TYPED |
324 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
325 } else if (origin_ == ORIGIN_INSTANT) {
326 load_url_params.transition_type = ui::PageTransitionFromInt(
327 ui::PAGE_TRANSITION_GENERATED |
328 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
330 load_url_params.override_user_agent =
331 prerender_manager_->config().is_overriding_user_agent ?
332 content::NavigationController::UA_OVERRIDE_TRUE :
333 content::NavigationController::UA_OVERRIDE_FALSE;
334 prerender_contents_.get()->GetController().LoadURLWithParams(load_url_params);
337 bool PrerenderContents::GetChildId(int* child_id) const {
338 CHECK(child_id);
339 DCHECK_GE(child_id_, -1);
340 *child_id = child_id_;
341 return child_id_ != -1;
344 bool PrerenderContents::GetRouteId(int* route_id) const {
345 CHECK(route_id);
346 DCHECK_GE(route_id_, -1);
347 *route_id = route_id_;
348 return route_id_ != -1;
351 void PrerenderContents::SetFinalStatus(FinalStatus final_status) {
352 DCHECK_GE(final_status, FINAL_STATUS_USED);
353 DCHECK_LT(final_status, FINAL_STATUS_MAX);
355 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
357 final_status_ = final_status;
360 PrerenderContents::~PrerenderContents() {
361 DCHECK_NE(FINAL_STATUS_MAX, final_status());
362 DCHECK(
363 prerendering_has_been_cancelled() || final_status() == FINAL_STATUS_USED);
364 DCHECK_NE(ORIGIN_MAX, origin());
366 prerender_manager_->RecordFinalStatusWithMatchCompleteStatus(
367 origin(), match_complete_status(), final_status());
369 bool used = final_status() == FINAL_STATUS_USED ||
370 final_status() == FINAL_STATUS_WOULD_HAVE_BEEN_USED;
371 prerender_manager_->RecordNetworkBytes(origin(), used, network_bytes_);
373 // Broadcast the removal of aliases.
374 for (content::RenderProcessHost::iterator host_iterator =
375 content::RenderProcessHost::AllHostsIterator();
376 !host_iterator.IsAtEnd();
377 host_iterator.Advance()) {
378 content::RenderProcessHost* host = host_iterator.GetCurrentValue();
379 host->Send(new PrerenderMsg_OnPrerenderRemoveAliases(alias_urls_));
382 // If we still have a WebContents, clean up anything we need to and then
383 // destroy it.
384 if (prerender_contents_.get())
385 delete ReleasePrerenderContents();
388 void PrerenderContents::AddObserver(Observer* observer) {
389 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
390 observer_list_.AddObserver(observer);
393 void PrerenderContents::RemoveObserver(Observer* observer) {
394 observer_list_.RemoveObserver(observer);
397 void PrerenderContents::Observe(int type,
398 const content::NotificationSource& source,
399 const content::NotificationDetails& details) {
400 switch (type) {
401 // TODO(davidben): Try to remove this in favor of relying on
402 // FINAL_STATUS_PROFILE_DESTROYED.
403 case chrome::NOTIFICATION_APP_TERMINATING:
404 Destroy(FINAL_STATUS_APP_TERMINATING);
405 return;
407 case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
408 if (prerender_contents_.get()) {
409 DCHECK_EQ(content::Source<WebContents>(source).ptr(),
410 prerender_contents_.get());
412 content::Details<RenderViewHost> new_render_view_host(details);
413 OnRenderViewHostCreated(new_render_view_host.ptr());
415 // Make sure the size of the RenderViewHost has been passed to the new
416 // RenderView. Otherwise, the size may not be sent until the
417 // RenderViewReady event makes it from the render process to the UI
418 // thread of the browser process. When the RenderView receives its
419 // size, is also sets itself to be visible, which would then break the
420 // visibility API.
421 new_render_view_host->WasResized();
422 prerender_contents_->WasHidden();
424 break;
427 default:
428 NOTREACHED() << "Unexpected notification sent.";
429 break;
433 void PrerenderContents::OnRenderViewHostCreated(
434 RenderViewHost* new_render_view_host) {
437 WebContents* PrerenderContents::CreateWebContents(
438 SessionStorageNamespace* session_storage_namespace) {
439 // TODO(ajwong): Remove the temporary map once prerendering is aware of
440 // multiple session storage namespaces per tab.
441 content::SessionStorageNamespaceMap session_storage_namespace_map;
442 session_storage_namespace_map[std::string()] = session_storage_namespace;
443 return WebContents::CreateWithSessionStorage(
444 WebContents::CreateParams(profile_), session_storage_namespace_map);
447 void PrerenderContents::NotifyPrerenderStart() {
448 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
449 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStart(this));
452 void PrerenderContents::NotifyPrerenderStopLoading() {
453 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStopLoading(this));
456 void PrerenderContents::NotifyPrerenderDomContentLoaded() {
457 FOR_EACH_OBSERVER(Observer, observer_list_,
458 OnPrerenderDomContentLoaded(this));
461 void PrerenderContents::NotifyPrerenderStop() {
462 DCHECK_NE(FINAL_STATUS_MAX, final_status_);
463 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStop(this));
464 observer_list_.Clear();
467 void PrerenderContents::NotifyPrerenderCreatedMatchCompleteReplacement(
468 PrerenderContents* replacement) {
469 FOR_EACH_OBSERVER(Observer, observer_list_,
470 OnPrerenderCreatedMatchCompleteReplacement(this,
471 replacement));
474 bool PrerenderContents::OnMessageReceived(const IPC::Message& message) {
475 bool handled = true;
476 // The following messages we do want to consume.
477 IPC_BEGIN_MESSAGE_MAP(PrerenderContents, message)
478 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CancelPrerenderForPrinting,
479 OnCancelPrerenderForPrinting)
480 IPC_MESSAGE_UNHANDLED(handled = false)
481 IPC_END_MESSAGE_MAP()
483 return handled;
486 bool PrerenderContents::CheckURL(const GURL& url) {
487 if (!url.SchemeIsHTTPOrHTTPS()) {
488 DCHECK_NE(MATCH_COMPLETE_REPLACEMENT_PENDING, match_complete_status_);
489 Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
490 return false;
492 if (match_complete_status_ != MATCH_COMPLETE_REPLACEMENT_PENDING &&
493 prerender_manager_->HasRecentlyBeenNavigatedTo(origin(), url)) {
494 Destroy(FINAL_STATUS_RECENTLY_VISITED);
495 return false;
497 return true;
500 bool PrerenderContents::AddAliasURL(const GURL& url) {
501 if (!CheckURL(url))
502 return false;
504 alias_urls_.push_back(url);
506 for (content::RenderProcessHost::iterator host_iterator =
507 content::RenderProcessHost::AllHostsIterator();
508 !host_iterator.IsAtEnd();
509 host_iterator.Advance()) {
510 content::RenderProcessHost* host = host_iterator.GetCurrentValue();
511 host->Send(new PrerenderMsg_OnPrerenderAddAlias(url));
514 return true;
517 bool PrerenderContents::Matches(
518 const GURL& url,
519 const SessionStorageNamespace* session_storage_namespace) const {
520 // TODO(davidben): Remove any consumers that pass in a NULL
521 // session_storage_namespace and only test with matches.
522 if (session_storage_namespace &&
523 session_storage_namespace_id_ != session_storage_namespace->id()) {
524 return false;
526 return std::count_if(alias_urls_.begin(), alias_urls_.end(),
527 std::bind2nd(std::equal_to<GURL>(), url)) != 0;
530 void PrerenderContents::RenderProcessGone(base::TerminationStatus status) {
531 Destroy(FINAL_STATUS_RENDERER_CRASHED);
534 void PrerenderContents::RenderFrameCreated(
535 content::RenderFrameHost* render_frame_host) {
536 // When a new RenderFrame is created for a prerendering WebContents, tell the
537 // new RenderFrame it's being used for prerendering before any navigations
538 // occur. Note that this is always triggered before the first navigation, so
539 // there's no need to send the message just after the WebContents is created.
540 render_frame_host->Send(new PrerenderMsg_SetIsPrerendering(
541 render_frame_host->GetRoutingID(), true));
544 void PrerenderContents::DidStopLoading() {
545 has_stopped_loading_ = true;
546 NotifyPrerenderStopLoading();
549 void PrerenderContents::DocumentLoadedInFrame(
550 content::RenderFrameHost* render_frame_host) {
551 if (!render_frame_host->GetParent())
552 NotifyPrerenderDomContentLoaded();
555 void PrerenderContents::DidStartProvisionalLoadForFrame(
556 content::RenderFrameHost* render_frame_host,
557 const GURL& validated_url,
558 bool is_error_page,
559 bool is_iframe_srcdoc) {
560 if (!render_frame_host->GetParent()) {
561 if (!CheckURL(validated_url))
562 return;
564 // Usually, this event fires if the user clicks or enters a new URL.
565 // Neither of these can happen in the case of an invisible prerender.
566 // So the cause is: Some JavaScript caused a new URL to be loaded. In that
567 // case, the spinner would start again in the browser, so we must reset
568 // has_stopped_loading_ so that the spinner won't be stopped.
569 has_stopped_loading_ = false;
570 has_finished_loading_ = false;
574 void PrerenderContents::DidFinishLoad(
575 content::RenderFrameHost* render_frame_host,
576 const GURL& validated_url) {
577 if (!render_frame_host->GetParent())
578 has_finished_loading_ = true;
581 void PrerenderContents::DidNavigateMainFrame(
582 const content::LoadCommittedDetails& details,
583 const content::FrameNavigateParams& params) {
584 // If the prerender made a second navigation entry, abort the prerender. This
585 // avoids having to correctly implement a complex history merging case (this
586 // interacts with location.replace) and correctly synchronize with the
587 // renderer. The final status may be monitored to see we need to revisit this
588 // decision. This does not affect client redirects as those do not push new
589 // history entries. (Calls to location.replace, navigations before onload, and
590 // <meta http-equiv=refresh> with timeouts under 1 second do not create
591 // entries in Blink.)
592 if (prerender_contents_->GetController().GetEntryCount() > 1) {
593 Destroy(FINAL_STATUS_NEW_NAVIGATION_ENTRY);
594 return;
597 // Add each redirect as an alias. |params.url| is included in
598 // |params.redirects|.
600 // TODO(davidben): We do not correctly patch up history for renderer-initated
601 // navigations which add history entries. http://crbug.com/305660.
602 for (size_t i = 0; i < params.redirects.size(); i++) {
603 if (!AddAliasURL(params.redirects[i]))
604 return;
608 void PrerenderContents::DidGetRedirectForResourceRequest(
609 content::RenderFrameHost* render_frame_host,
610 const content::ResourceRedirectDetails& details) {
611 // DidGetRedirectForResourceRequest can come for any resource on a page. If
612 // it's a redirect on the top-level resource, the name needs to be remembered
613 // for future matching, and if it redirects to an https resource, it needs to
614 // be canceled. If a subresource is redirected, nothing changes.
615 if (details.resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
616 return;
617 CheckURL(details.new_url);
620 void PrerenderContents::Destroy(FinalStatus final_status) {
621 DCHECK_NE(final_status, FINAL_STATUS_USED);
623 if (prerendering_has_been_cancelled_)
624 return;
626 SetFinalStatus(final_status);
628 prerendering_has_been_cancelled_ = true;
629 prerender_manager_->AddToHistory(this);
630 prerender_manager_->MoveEntryToPendingDelete(this, final_status);
632 // Note that if this PrerenderContents was made into a MatchComplete
633 // replacement by MoveEntryToPendingDelete, NotifyPrerenderStop will
634 // not reach the PrerenderHandle. Rather
635 // OnPrerenderCreatedMatchCompleteReplacement will propogate that
636 // information to the referer.
637 if (!prerender_manager_->IsControlGroup() &&
638 (prerendering_has_started() ||
639 match_complete_status() == MATCH_COMPLETE_REPLACEMENT)) {
640 NotifyPrerenderStop();
644 base::ProcessMetrics* PrerenderContents::MaybeGetProcessMetrics() {
645 if (process_metrics_.get() == NULL) {
646 // If a PrenderContents hasn't started prerending, don't be fully formed.
647 if (!GetRenderViewHost() || !GetRenderViewHost()->GetProcess())
648 return NULL;
649 base::ProcessHandle handle = GetRenderViewHost()->GetProcess()->GetHandle();
650 if (handle == base::kNullProcessHandle)
651 return NULL;
652 #if !defined(OS_MACOSX)
653 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
654 #else
655 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(
656 handle,
657 content::BrowserChildProcessHost::GetPortProvider()));
658 #endif
661 return process_metrics_.get();
664 void PrerenderContents::DestroyWhenUsingTooManyResources() {
665 base::ProcessMetrics* metrics = MaybeGetProcessMetrics();
666 if (metrics == NULL)
667 return;
669 size_t private_bytes, shared_bytes;
670 if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes) &&
671 private_bytes > prerender_manager_->config().max_bytes) {
672 Destroy(FINAL_STATUS_MEMORY_LIMIT_EXCEEDED);
676 WebContents* PrerenderContents::ReleasePrerenderContents() {
677 prerender_contents_->SetDelegate(NULL);
678 content::WebContentsObserver::Observe(NULL);
680 // Clear the task manager tag we added earlier to our
681 // WebContents since it's no longer a prerender contents.
682 task_management::WebContentsTags::ClearTag(prerender_contents_.get());
684 return prerender_contents_.release();
687 RenderViewHost* PrerenderContents::GetRenderViewHostMutable() {
688 return const_cast<RenderViewHost*>(GetRenderViewHost());
691 const RenderViewHost* PrerenderContents::GetRenderViewHost() const {
692 if (!prerender_contents_.get())
693 return NULL;
694 return prerender_contents_->GetRenderViewHost();
697 void PrerenderContents::DidNavigate(
698 const history::HistoryAddPageArgs& add_page_args) {
699 add_page_vector_.push_back(add_page_args);
702 void PrerenderContents::CommitHistory(WebContents* tab) {
703 HistoryTabHelper* history_tab_helper = HistoryTabHelper::FromWebContents(tab);
704 for (size_t i = 0; i < add_page_vector_.size(); ++i)
705 history_tab_helper->UpdateHistoryForNavigation(add_page_vector_[i]);
708 base::Value* PrerenderContents::GetAsValue() const {
709 if (!prerender_contents_.get())
710 return NULL;
711 base::DictionaryValue* dict_value = new base::DictionaryValue();
712 dict_value->SetString("url", prerender_url_.spec());
713 base::TimeTicks current_time = base::TimeTicks::Now();
714 base::TimeDelta duration = current_time - load_start_time_;
715 dict_value->SetInteger("duration", duration.InSeconds());
716 dict_value->SetBoolean("is_loaded", prerender_contents_ &&
717 !prerender_contents_->IsLoading());
718 return dict_value;
721 bool PrerenderContents::IsCrossSiteNavigationPending() const {
722 if (!prerender_contents_)
723 return false;
724 return (prerender_contents_->GetSiteInstance() !=
725 prerender_contents_->GetPendingSiteInstance());
728 void PrerenderContents::PrepareForUse() {
729 SetFinalStatus(FINAL_STATUS_USED);
731 if (prerender_contents_.get()) {
732 prerender_contents_->SendToAllFrames(
733 new PrerenderMsg_SetIsPrerendering(MSG_ROUTING_NONE, false));
736 NotifyPrerenderStop();
738 BrowserThread::PostTask(
739 BrowserThread::IO,
740 FROM_HERE,
741 base::Bind(&ResumeThrottles, resource_throttles_));
742 resource_throttles_.clear();
745 void PrerenderContents::OnCancelPrerenderForPrinting() {
746 Destroy(FINAL_STATUS_WINDOW_PRINT);
749 void PrerenderContents::AddResourceThrottle(
750 const base::WeakPtr<PrerenderResourceThrottle>& throttle) {
751 resource_throttles_.push_back(throttle);
754 void PrerenderContents::AddNetworkBytes(int64 bytes) {
755 network_bytes_ += bytes;
758 } // namespace prerender