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