// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/renderer/prerender/prerender_dispatcher.h" #include "base/logging.h" #include "chrome/common/prerender_messages.h" #include "chrome/renderer/prerender/prerender_extra_data.h" #include "content/public/common/referrer.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "third_party/WebKit/public/platform/WebPrerenderingSupport.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "url/gurl.h" namespace prerender { using blink::WebPrerender; using blink::WebPrerenderingSupport; PrerenderDispatcher::PrerenderDispatcher() { WebPrerenderingSupport::initialize(this); } PrerenderDispatcher::~PrerenderDispatcher() { WebPrerenderingSupport::shutdown(); } bool PrerenderDispatcher::IsPrerenderURL(const GURL& url) const { return running_prerender_urls_.count(url) >= 1; } void PrerenderDispatcher::OnPrerenderStart(int prerender_id) { std::map<int, WebPrerender>::iterator it = prerenders_.find(prerender_id); if (it == prerenders_.end()) return; WebPrerender& prerender = it->second; // The prerender should only be null in unit tests. if (prerender.isNull()) return; prerender.didStartPrerender(); } void PrerenderDispatcher::OnPrerenderStopLoading(int prerender_id) { std::map<int, WebPrerender>::iterator it = prerenders_.find(prerender_id); if (it == prerenders_.end()) return; WebPrerender& prerender = it->second; DCHECK(!prerender.isNull()) << "OnPrerenderStopLoading shouldn't be called from a unit test, the only" << "context in which a WebPrerender in the dispatcher can be null."; prerender.didSendLoadForPrerender(); } void PrerenderDispatcher::OnPrerenderAddAlias(const GURL& alias) { running_prerender_urls_.insert(alias); } void PrerenderDispatcher::OnPrerenderRemoveAliases( const std::vector<GURL>& aliases) { for (size_t i = 0; i < aliases.size(); ++i) { std::multiset<GURL>::iterator it = running_prerender_urls_.find(aliases[i]); if (it != running_prerender_urls_.end()) { running_prerender_urls_.erase(it); } } } void PrerenderDispatcher::OnPrerenderStop(int prerender_id) { std::map<int, WebPrerender>::iterator it = prerenders_.find(prerender_id); if (it == prerenders_.end()) return; WebPrerender& prerender = it->second; // The prerender should only be null in unit tests. if (!prerender.isNull()) prerender.didStopPrerender(); // TODO(cbentzel): We'd also want to send the map of active prerenders when // creating a new render process, so the Add/Remove go relative to that. // This may not be that big of a deal in practice, since the newly created tab // is unlikely to go to the prerendered page. prerenders_.erase(prerender_id); } bool PrerenderDispatcher::OnControlMessageReceived( const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrerenderDispatcher, message) IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderStart, OnPrerenderStart) IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderStopLoading, OnPrerenderStopLoading) IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderAddAlias, OnPrerenderAddAlias) IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderRemoveAliases, OnPrerenderRemoveAliases) IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderStop, OnPrerenderStop) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void PrerenderDispatcher::add(const WebPrerender& prerender) { const PrerenderExtraData& extra_data = PrerenderExtraData::FromPrerender(prerender); if (prerenders_.count(extra_data.prerender_id()) != 0) { // TODO(gavinp): Determine why these apparently duplicate adds occur. return; } prerenders_[extra_data.prerender_id()] = prerender; content::RenderThread::Get()->Send(new PrerenderHostMsg_AddLinkRelPrerender( extra_data.prerender_id(), GURL(prerender.url()), content::Referrer(GURL(prerender.referrer()), prerender.referrerPolicy()), extra_data.size(), extra_data.render_view_route_id())); } void PrerenderDispatcher::cancel(const WebPrerender& prerender) { const PrerenderExtraData& extra_data = PrerenderExtraData::FromPrerender(prerender); content::RenderThread::Get()->Send( new PrerenderHostMsg_CancelLinkRelPrerender(extra_data.prerender_id())); // The browser will not send an OnPrerenderStop (the prerender may have even // been canceled before it was started), so release it to avoid a // leak. Moreover, if it did, the PrerenderClient in Blink will have been // detached already. prerenders_.erase(extra_data.prerender_id()); } void PrerenderDispatcher::abandon(const WebPrerender& prerender) { const PrerenderExtraData& extra_data = PrerenderExtraData::FromPrerender(prerender); content::RenderThread::Get()->Send( new PrerenderHostMsg_AbandonLinkRelPrerender(extra_data.prerender_id())); // The browser will not send an OnPrerenderStop (the prerender may have even // been canceled before it was started), so release it to avoid a // leak. Moreover, if it did, the PrerenderClient in Blink will have been // detached already. prerenders_.erase(extra_data.prerender_id()); } } // namespace prerender