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
PrerenderDispatcher()23 PrerenderDispatcher::PrerenderDispatcher() {
24 WebPrerenderingSupport::initialize(this);
25 }
26
~PrerenderDispatcher()27 PrerenderDispatcher::~PrerenderDispatcher() {
28 WebPrerenderingSupport::shutdown();
29 }
30
IsPrerenderURL(const GURL & url) const31 bool PrerenderDispatcher::IsPrerenderURL(const GURL& url) const {
32 return running_prerender_urls_.count(url) >= 1;
33 }
34
OnPrerenderStart(int prerender_id)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
OnPrerenderStopLoading(int prerender_id)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
OnPrerenderAddAlias(const GURL & alias)62 void PrerenderDispatcher::OnPrerenderAddAlias(const GURL& alias) {
63 running_prerender_urls_.insert(alias);
64 }
65
OnPrerenderRemoveAliases(const std::vector<GURL> & aliases)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
OnPrerenderStop(int prerender_id)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
OnControlMessageReceived(const IPC::Message & message)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
add(const WebPrerender & prerender)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
cancel(const WebPrerender & prerender)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
abandon(const WebPrerender & prerender)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