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/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