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