Home | History | Annotate | Download | only in history
      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/browser/history/history_tab_helper.h"
      6 
      7 #include <utility>
      8 
      9 #include "chrome/browser/history/history_service.h"
     10 #include "chrome/browser/history/history_service_factory.h"
     11 #include "chrome/browser/prerender/prerender_contents.h"
     12 #include "chrome/browser/prerender/prerender_manager.h"
     13 #include "chrome/browser/prerender/prerender_manager_factory.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/common/render_messages.h"
     16 #include "content/public/browser/navigation_details.h"
     17 #include "content/public/browser/navigation_entry.h"
     18 #include "content/public/browser/notification_details.h"
     19 #include "content/public/browser/notification_source.h"
     20 #include "content/public/browser/notification_types.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/browser/web_contents_delegate.h"
     23 #include "content/public/common/frame_navigate_params.h"
     24 
     25 #if !defined(OS_ANDROID)
     26 #include "chrome/browser/ui/browser.h"
     27 #include "chrome/browser/ui/browser_finder.h"
     28 #endif
     29 
     30 using content::NavigationEntry;
     31 using content::WebContents;
     32 
     33 DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper);
     34 
     35 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
     36     : content::WebContentsObserver(web_contents),
     37       received_page_title_(false) {
     38   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
     39                  content::Source<WebContents>(web_contents));
     40 }
     41 
     42 HistoryTabHelper::~HistoryTabHelper() {
     43 }
     44 
     45 void HistoryTabHelper::UpdateHistoryForNavigation(
     46     const history::HistoryAddPageArgs& add_page_args) {
     47   HistoryService* hs = GetHistoryService();
     48   if (hs)
     49     GetHistoryService()->AddPage(add_page_args);
     50 }
     51 
     52 void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
     53   HistoryService* hs = GetHistoryService();
     54   if (hs)
     55     hs->SetPageTitle(entry.GetVirtualURL(),
     56                      entry.GetTitleForDisplay(std::string()));
     57 }
     58 
     59 history::HistoryAddPageArgs
     60 HistoryTabHelper::CreateHistoryAddPageArgs(
     61     const GURL& virtual_url,
     62     base::Time timestamp,
     63     bool did_replace_entry,
     64     const content::FrameNavigateParams& params) {
     65   history::HistoryAddPageArgs add_page_args(
     66       params.url, timestamp, web_contents(), params.page_id,
     67       params.referrer.url, params.redirects, params.transition,
     68       history::SOURCE_BROWSED, did_replace_entry);
     69   if (content::PageTransitionIsMainFrame(params.transition) &&
     70       virtual_url != params.url) {
     71     // Hack on the "virtual" URL so that it will appear in history. For some
     72     // types of URLs, we will display a magic URL that is different from where
     73     // the page is actually navigated. We want the user to see in history what
     74     // they saw in the URL bar, so we add the virtual URL as a redirect.  This
     75     // only applies to the main frame, as the virtual URL doesn't apply to
     76     // sub-frames.
     77     add_page_args.url = virtual_url;
     78     if (!add_page_args.redirects.empty())
     79       add_page_args.redirects.back() = virtual_url;
     80   }
     81   return add_page_args;
     82 }
     83 
     84 bool HistoryTabHelper::OnMessageReceived(const IPC::Message& message) {
     85   bool handled = true;
     86   IPC_BEGIN_MESSAGE_MAP(HistoryTabHelper, message)
     87     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageContents, OnPageContents)
     88     IPC_MESSAGE_UNHANDLED(handled = false)
     89   IPC_END_MESSAGE_MAP()
     90 
     91   return handled;
     92 }
     93 
     94 void HistoryTabHelper::DidNavigateMainFrame(
     95     const content::LoadCommittedDetails& details,
     96     const content::FrameNavigateParams& params) {
     97   // Allow the new page to set the title again.
     98   received_page_title_ = false;
     99 }
    100 
    101 void HistoryTabHelper::DidNavigateAnyFrame(
    102     const content::LoadCommittedDetails& details,
    103     const content::FrameNavigateParams& params) {
    104   // Update history. Note that this needs to happen after the entry is complete,
    105   // which WillNavigate[Main,Sub]Frame will do before this function is called.
    106   if (!params.should_update_history)
    107     return;
    108 
    109   // Most of the time, the displayURL matches the loaded URL, but for about:
    110   // URLs, we use a data: URL as the real value.  We actually want to save the
    111   // about: URL to the history db and keep the data: URL hidden. This is what
    112   // the WebContents' URL getter does.
    113   const history::HistoryAddPageArgs& add_page_args =
    114       CreateHistoryAddPageArgs(
    115           web_contents()->GetURL(), details.entry->GetTimestamp(),
    116           details.did_replace_entry, params);
    117 
    118   prerender::PrerenderManager* prerender_manager =
    119       prerender::PrerenderManagerFactory::GetForProfile(
    120           Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
    121   if (prerender_manager) {
    122     prerender::PrerenderContents* prerender_contents =
    123         prerender_manager->GetPrerenderContents(web_contents());
    124     if (prerender_contents) {
    125       prerender_contents->DidNavigate(add_page_args);
    126       return;
    127     }
    128   }
    129 
    130 #if !defined(OS_ANDROID)
    131   // Don't update history if this web contents isn't associatd with a tab.
    132   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
    133   if (!browser || browser->is_app())
    134     return;
    135 #endif
    136 
    137   UpdateHistoryForNavigation(add_page_args);
    138 }
    139 
    140 void HistoryTabHelper::Observe(int type,
    141                                const content::NotificationSource& source,
    142                                const content::NotificationDetails& details) {
    143   DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED);
    144   std::pair<content::NavigationEntry*, bool>* title =
    145       content::Details<std::pair<content::NavigationEntry*, bool> >(
    146           details).ptr();
    147 
    148   if (received_page_title_)
    149     return;
    150 
    151   if (title->first) {
    152     UpdateHistoryPageTitle(*title->first);
    153     received_page_title_ = title->second;
    154   }
    155 }
    156 
    157 void HistoryTabHelper::OnPageContents(const GURL& url,
    158                                       const string16& contents) {
    159   // Don't index any https pages. People generally don't want their bank
    160   // accounts, etc. indexed on their computer, especially since some of these
    161   // things are not marked cachable.
    162   // TODO(brettw) we may want to consider more elaborate heuristics such as
    163   // the cachability of the page. We may also want to consider subframes (this
    164   // test will still index subframes if the subframe is SSL).
    165   // TODO(zelidrag) bug chromium-os:2808 - figure out if we want to reenable
    166   // content indexing for chromeos in some future releases.
    167 #if !defined(OS_CHROMEOS)
    168   if (!url.SchemeIsSecure()) {
    169     HistoryService* hs = GetHistoryService();
    170     if (hs)
    171       hs->SetPageContents(url, contents);
    172   }
    173 #endif
    174 }
    175 
    176 HistoryService* HistoryTabHelper::GetHistoryService() {
    177   Profile* profile =
    178       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
    179   if (profile->IsOffTheRecord())
    180     return NULL;
    181 
    182   return HistoryServiceFactory::GetForProfile(profile,
    183                                               Profile::IMPLICIT_ACCESS);
    184 }
    185 
    186 void HistoryTabHelper::WebContentsDestroyed(WebContents* tab) {
    187   // TODO(sky): nuke this since no one is using visit_duration (and this is all
    188   // wrong).
    189 
    190   // We update the history for this URL.
    191   // The content returned from web_contents() has been destroyed by now.
    192   // We need to use tab value directly.
    193   Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
    194   if (profile->IsOffTheRecord())
    195     return;
    196 
    197   HistoryService* hs =
    198       HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
    199   if (hs) {
    200     NavigationEntry* entry = tab->GetController().GetLastCommittedEntry();
    201     if (entry) {
    202       hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(),
    203                                 base::Time::Now());
    204     }
    205   }
    206 }
    207