Home | History | Annotate | Download | only in prerender
      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