1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/in_memory_history_backend.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <set> 821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <vector> 921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h" 113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/time.h" 123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/in_memory_database.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/in_memory_url_index.h" 173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/history/url_database.h" 1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history { 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If a page becomes starred we use this id in place of the real starred id. 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See note in OnURLsStarred. 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const StarID kBogusStarredID = 0x0FFFFFFF; 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochInMemoryHistoryBackend::InMemoryHistoryBackend() 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : profile_(NULL) { 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochInMemoryHistoryBackend::~InMemoryHistoryBackend() { 34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (index_.get()) 35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen index_->ShutDown(); 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool InMemoryHistoryBackend::Init(const FilePath& history_filename, 39dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const FilePath& history_dir, 40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick URLDatabase* db, 41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const std::string& languages) { 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch db_.reset(new InMemoryDatabase); 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool success = db_->InitFromDisk(history_filename); 44dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (CommandLine::ForCurrentProcess()->HasSwitch( 45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen switches::kEnableHistoryQuickProvider) && 46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen !CommandLine::ForCurrentProcess()->HasSwitch( 47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen switches::kDisableHistoryQuickProvider)) { 48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen index_.reset(new InMemoryURLIndex(history_dir)); 49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick index_->Init(db, languages); 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return success; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InMemoryHistoryBackend::AttachToHistoryService(Profile* profile) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!db_.get()) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = profile; 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(evanm): this is currently necessitated by generate_profile, which 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // runs without a browser process. generate_profile should really create 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a browser process, at which point this check can then be nuked. 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!g_browser_process) 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Register for the notifications we care about. 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only want notifications for the associated profile. 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile> source(profile_); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::HISTORY_URL_VISITED, source); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, source); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, source); 75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch registrar_.Add(this, NotificationType::HISTORY_KEYWORD_SEARCH_TERM_UPDATED, 76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch source); 77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch registrar_.Add(this, NotificationType::TEMPLATE_URL_REMOVED, source); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InMemoryHistoryBackend::Observe(NotificationType type, 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type.value) { 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::HISTORY_URL_VISITED: { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<history::URLVisitedDetails> visited_details(details); 86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch PageTransition::Type primary_type = 87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch PageTransition::StripQualifier(visited_details->transition); 88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (visited_details->row.typed_count() > 0 || 893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen primary_type == PageTransition::KEYWORD || 903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen HasKeyword(visited_details->row.url())) { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLsModifiedDetails modified_details; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch modified_details.changed_urls.push_back(visited_details->row); 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnTypedURLsModified(modified_details); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 97513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch case NotificationType::HISTORY_KEYWORD_SEARCH_TERM_UPDATED: 98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch OnKeywordSearchTermUpdated( 99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *Details<history::KeywordSearchTermDetails>(details).ptr()); 100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch break; 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::HISTORY_TYPED_URLS_MODIFIED: 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnTypedURLsModified( 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *Details<history::URLsModifiedDetails>(details).ptr()); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::HISTORY_URLS_DELETED: 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnURLsDeleted(*Details<history::URLsDeletedDetails>(details).ptr()); 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch case NotificationType::TEMPLATE_URL_REMOVED: 109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch db_->DeleteAllSearchTermsForKeyword( 110513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch *(Details<TemplateURLID>(details).ptr())); 111513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch break; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For simplicity, the unit tests send us all notifications, even when 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we haven't registered for them, so don't assert here. 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InMemoryHistoryBackend::OnTypedURLsModified( 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const URLsModifiedDetails& details) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(db_.get()); 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add or update the URLs. 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(brettw) currently the rows in the in-memory database don't match the 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // IDs in the main database. This sucks. Instead of Add and Remove, we should 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have Sync(), which would take the ID if it's given and add it. 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<history::URLRow>::const_iterator i; 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (i = details.changed_urls.begin(); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != details.changed_urls.end(); i++) { 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLID id = db_->GetRowForURL(i->url(), NULL); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (id) 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch db_->UpdateURLRow(id, *i); 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen id = db_->AddURL(*i); 136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (index_.get()) 137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen index_->UpdateURL(id, *i); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) { 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(db_.get()); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (details.all_history) { 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When all history is deleted, the individual URLs won't be listed. Just 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // create a new database to quickly clear everything out. 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch db_.reset(new InMemoryDatabase); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!db_->InitFromScratch()) 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch db_.reset(); 150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (index_.get()) 151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen index_->ReloadFromHistory(db_.get(), true); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Delete all matching URLs in our database. 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<GURL>::const_iterator i = details.urls.begin(); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != details.urls.end(); ++i) { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLID id = db_->GetRowForURL(*i, NULL); 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (id) { 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We typically won't have most of them since we only have a subset of 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // history, so ignore errors. 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch db_->DeleteURLRow(id); 163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (index_.get()) 164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen index_->DeleteURL(id); 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid InMemoryHistoryBackend::OnKeywordSearchTermUpdated( 170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const KeywordSearchTermDetails& details) { 171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // The url won't exist for new search terms (as the user hasn't typed it), so 172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // we force it to be added. If we end up adding a URL it won't be 173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // autocompleted as the typed count is 0. 174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch URLRow url_row; 175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch URLID url_id; 176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!db_->GetRowForURL(details.url, &url_row)) { 177513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Because this row won't have a typed count the title and other stuff 178513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // doesn't matter. If the user ends up typing the url we'll update the title 179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // in OnTypedURLsModified. 180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch URLRow new_row(details.url); 181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch new_row.set_last_visit(base::Time::Now()); 182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch url_id = db_->AddURL(new_row); 183513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!url_id) 184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return; // Error adding. 185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } else { 186513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch url_id = url_row.id(); 187513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch db_->SetKeywordSearchTermsForURL(url_id, details.keyword_id, details.term); 190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 1923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool InMemoryHistoryBackend::HasKeyword(const GURL& url) { 1933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen URLID id = db_->GetRowForURL(url, NULL); 1943f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (!id) 1953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return false; 1963f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return db_->GetKeywordSearchTermRow(id, NULL); 1983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} 1993f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace history 201