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