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. 4 5 #include "chrome/renderer/prerender/prerender_dispatcher.h" 6 7 #include "base/logging.h" 8 #include "chrome/common/prerender_messages.h" 9 #include "chrome/renderer/prerender/prerender_extra_data.h" 10 #include "content/public/common/referrer.h" 11 #include "content/public/renderer/render_thread.h" 12 #include "content/public/renderer/render_view.h" 13 #include "third_party/WebKit/public/platform/WebPrerenderingSupport.h" 14 #include "third_party/WebKit/public/platform/WebString.h" 15 #include "third_party/WebKit/public/platform/WebURL.h" 16 #include "url/gurl.h" 17 18 namespace prerender { 19 20 using blink::WebPrerender; 21 using blink::WebPrerenderingSupport; 22 23 PrerenderDispatcher::PrerenderDispatcher() { 24 WebPrerenderingSupport::initialize(this); 25 } 26 27 PrerenderDispatcher::~PrerenderDispatcher() { 28 WebPrerenderingSupport::shutdown(); 29 } 30 31 bool PrerenderDispatcher::IsPrerenderURL(const GURL& url) const { 32 return running_prerender_urls_.count(url) >= 1; 33 } 34 35 void PrerenderDispatcher::OnPrerenderStart(int prerender_id) { 36 std::map<int, WebPrerender>::iterator it = prerenders_.find(prerender_id); 37 if (it == prerenders_.end()) 38 return; 39 40 WebPrerender& prerender = it->second; 41 42 // The prerender should only be null in unit tests. 43 if (prerender.isNull()) 44 return; 45 46 prerender.didStartPrerender(); 47 } 48 49 void PrerenderDispatcher::OnPrerenderStopLoading(int prerender_id) { 50 std::map<int, WebPrerender>::iterator it = prerenders_.find(prerender_id); 51 if (it == prerenders_.end()) 52 return; 53 54 WebPrerender& prerender = it->second; 55 DCHECK(!prerender.isNull()) 56 << "OnPrerenderStopLoading shouldn't be called from a unit test, the only" 57 << "context in which a WebPrerender in the dispatcher can be null."; 58 59 prerender.didSendLoadForPrerender(); 60 } 61 62 void PrerenderDispatcher::OnPrerenderAddAlias(const GURL& alias) { 63 running_prerender_urls_.insert(alias); 64 } 65 66 void PrerenderDispatcher::OnPrerenderRemoveAliases( 67 const std::vector<GURL>& aliases) { 68 for (size_t i = 0; i < aliases.size(); ++i) { 69 std::multiset<GURL>::iterator it = running_prerender_urls_.find(aliases[i]); 70 if (it != running_prerender_urls_.end()) { 71 running_prerender_urls_.erase(it); 72 } 73 } 74 } 75 76 void PrerenderDispatcher::OnPrerenderStop(int prerender_id) { 77 std::map<int, WebPrerender>::iterator it = prerenders_.find(prerender_id); 78 if (it == prerenders_.end()) 79 return; 80 WebPrerender& prerender = it->second; 81 82 // The prerender should only be null in unit tests. 83 if (!prerender.isNull()) 84 prerender.didStopPrerender(); 85 86 // TODO(cbentzel): We'd also want to send the map of active prerenders when 87 // creating a new render process, so the Add/Remove go relative to that. 88 // This may not be that big of a deal in practice, since the newly created tab 89 // is unlikely to go to the prerendered page. 90 prerenders_.erase(prerender_id); 91 } 92 93 bool PrerenderDispatcher::OnControlMessageReceived( 94 const IPC::Message& message) { 95 bool handled = true; 96 IPC_BEGIN_MESSAGE_MAP(PrerenderDispatcher, message) 97 IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderStart, OnPrerenderStart) 98 IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderStopLoading, 99 OnPrerenderStopLoading) 100 IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderAddAlias, OnPrerenderAddAlias) 101 IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderRemoveAliases, 102 OnPrerenderRemoveAliases) 103 IPC_MESSAGE_HANDLER(PrerenderMsg_OnPrerenderStop, OnPrerenderStop) 104 IPC_MESSAGE_UNHANDLED(handled = false) 105 IPC_END_MESSAGE_MAP() 106 107 return handled; 108 } 109 110 void PrerenderDispatcher::add(const WebPrerender& prerender) { 111 const PrerenderExtraData& extra_data = 112 PrerenderExtraData::FromPrerender(prerender); 113 if (prerenders_.count(extra_data.prerender_id()) != 0) { 114 // TODO(gavinp): Determine why these apparently duplicate adds occur. 115 return; 116 } 117 118 prerenders_[extra_data.prerender_id()] = prerender; 119 120 content::RenderThread::Get()->Send(new PrerenderHostMsg_AddLinkRelPrerender( 121 extra_data.prerender_id(), GURL(prerender.url()), 122 content::Referrer(GURL(prerender.referrer()), 123 prerender.referrerPolicy()), 124 extra_data.size(), extra_data.render_view_route_id())); 125 } 126 127 void PrerenderDispatcher::cancel(const WebPrerender& prerender) { 128 const PrerenderExtraData& extra_data = 129 PrerenderExtraData::FromPrerender(prerender); 130 content::RenderThread::Get()->Send( 131 new PrerenderHostMsg_CancelLinkRelPrerender(extra_data.prerender_id())); 132 // The browser will not send an OnPrerenderStop (the prerender may have even 133 // been canceled before it was started), so release it to avoid a 134 // leak. Moreover, if it did, the PrerenderClient in Blink will have been 135 // detached already. 136 prerenders_.erase(extra_data.prerender_id()); 137 } 138 139 void PrerenderDispatcher::abandon(const WebPrerender& prerender) { 140 const PrerenderExtraData& extra_data = 141 PrerenderExtraData::FromPrerender(prerender); 142 content::RenderThread::Get()->Send( 143 new PrerenderHostMsg_AbandonLinkRelPrerender(extra_data.prerender_id())); 144 // The browser will not send an OnPrerenderStop (the prerender may have even 145 // been canceled before it was started), so release it to avoid a 146 // leak. Moreover, if it did, the PrerenderClient in Blink will have been 147 // detached already. 148 prerenders_.erase(extra_data.prerender_id()); 149 } 150 151 } // namespace prerender 152