instant_service.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright 2013 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/search/instant_service.h"
6
7#include "base/strings/string_number_conversions.h"
8#include "chrome/browser/history/history_notifications.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/search/instant_io_context.h"
11#include "chrome/browser/search/instant_service_factory.h"
12#include "chrome/browser/search/local_ntp_source.h"
13#include "chrome/browser/search/most_visited_iframe_source.h"
14#include "chrome/browser/search/suggestion_iframe_source.h"
15#include "chrome/browser/ui/webui/favicon_source.h"
16#include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
17#include "chrome/browser/ui/webui/theme_source.h"
18#include "chrome/common/chrome_notification_types.h"
19#include "content/public/browser/browser_thread.h"
20#include "content/public/browser/notification_service.h"
21#include "content/public/browser/notification_types.h"
22#include "content/public/browser/render_process_host.h"
23#include "content/public/browser/url_data_source.h"
24#include "googleurl/src/gurl.h"
25#include "net/url_request/url_request.h"
26
27using content::BrowserThread;
28
29InstantService::InstantService(Profile* profile)
30    : profile_(profile),
31      most_visited_item_cache_(kMaxInstantMostVisitedItemCacheSize) {
32  // Stub for unit tests.
33  if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
34    return;
35
36  registrar_.Add(this,
37                 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
38                 content::NotificationService::AllSources());
39
40  instant_io_context_ = new InstantIOContext();
41
42  if (profile_ && profile_->GetResourceContext()) {
43    BrowserThread::PostTask(
44        BrowserThread::IO, FROM_HERE,
45        base::Bind(&InstantIOContext::SetUserDataOnIO,
46                   profile->GetResourceContext(), instant_io_context_));
47  }
48
49  // Set up the data sources that Instant uses on the NTP.
50#if defined(ENABLE_THEMES)
51  content::URLDataSource::Add(profile, new ThemeSource(profile));
52#endif
53  content::URLDataSource::Add(profile, new ThumbnailSource(profile));
54  content::URLDataSource::Add(profile, new FaviconSource(
55      profile, FaviconSource::FAVICON));
56  content::URLDataSource::Add(profile, new LocalNtpSource());
57  content::URLDataSource::Add(profile, new SuggestionIframeSource());
58  content::URLDataSource::Add(profile, new MostVisitedIframeSource());
59}
60
61InstantService::~InstantService() {
62}
63
64// static
65const std::string InstantService::MaybeTranslateInstantPathOnUI(
66    Profile* profile, const std::string& path) {
67  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
68  InstantService* instant_service =
69      InstantServiceFactory::GetForProfile(profile);
70  if (!instant_service)
71    return path;
72
73  InstantRestrictedID restricted_id = 0;
74  DCHECK_EQ(sizeof(InstantRestrictedID), sizeof(int));
75  if (base::StringToInt(path, &restricted_id)) {
76    InstantMostVisitedItem item;
77    if (instant_service->GetMostVisitedItemForID(restricted_id, &item))
78      return item.url.spec();
79  }
80  return path;
81}
82
83const std::string InstantService::MaybeTranslateInstantPathOnIO(
84    const net::URLRequest* request, const std::string& path) {
85  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
86
87  InstantRestrictedID restricted_id = 0;
88  DCHECK_EQ(sizeof(InstantRestrictedID), sizeof(int));
89  if (base::StringToInt(path, &restricted_id)) {
90    GURL url;
91    if (InstantIOContext::GetURLForMostVisitedItemID(request,
92                                                     restricted_id,
93                                                     &url)) {
94      return url.spec();
95    }
96  }
97  return path;
98}
99
100// static
101bool InstantService::IsInstantPath(const GURL& url) {
102  // Strip leading slash.
103  std::string path = url.path().substr(1);
104
105  // Check that path is of Most Visited item ID form.
106  InstantRestrictedID dummy = 0;
107  return base::StringToInt(path, &dummy);
108}
109
110void InstantService::AddInstantProcess(int process_id) {
111  process_ids_.insert(process_id);
112
113  if (instant_io_context_) {
114    BrowserThread::PostTask(
115        BrowserThread::IO, FROM_HERE,
116        base::Bind(&InstantIOContext::AddInstantProcessOnIO,
117                   instant_io_context_, process_id));
118  }
119}
120
121bool InstantService::IsInstantProcess(int process_id) const {
122  return process_ids_.find(process_id) != process_ids_.end();
123}
124
125void InstantService::AddMostVisitedItems(
126    const std::vector<InstantMostVisitedItem>& items) {
127  most_visited_item_cache_.AddItems(items);
128
129  // Post task to the IO thread to copy the data.
130  if (instant_io_context_) {
131    std::vector<InstantMostVisitedItemIDPair> items;
132    most_visited_item_cache_.GetCurrentItems(&items);
133    BrowserThread::PostTask(
134        BrowserThread::IO, FROM_HERE,
135        base::Bind(&InstantIOContext::AddMostVisitedItemsOnIO,
136                   instant_io_context_,
137                   items));
138  }
139}
140
141void InstantService::GetCurrentMostVisitedItems(
142    std::vector<InstantMostVisitedItemIDPair>* items) const {
143  most_visited_item_cache_.GetCurrentItems(items);
144}
145
146bool InstantService::GetMostVisitedItemForID(
147    InstantRestrictedID most_visited_item_id,
148    InstantMostVisitedItem* item) const {
149  return most_visited_item_cache_.GetItemWithRestrictedID(
150      most_visited_item_id, item);
151}
152
153void InstantService::Shutdown() {
154  process_ids_.clear();
155
156  if (instant_io_context_) {
157    BrowserThread::PostTask(
158        BrowserThread::IO, FROM_HERE,
159        base::Bind(&InstantIOContext::ClearInstantProcessesOnIO,
160                   instant_io_context_));
161  }
162  instant_io_context_ = NULL;
163}
164
165void InstantService::Observe(int type,
166                             const content::NotificationSource& source,
167                             const content::NotificationDetails& details) {
168  switch (type) {
169    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
170      int process_id =
171          content::Source<content::RenderProcessHost>(source)->GetID();
172      process_ids_.erase(process_id);
173
174      if (instant_io_context_) {
175        BrowserThread::PostTask(
176            BrowserThread::IO, FROM_HERE,
177            base::Bind(&InstantIOContext::RemoveInstantProcessOnIO,
178                       instant_io_context_, process_id));
179      }
180      break;
181    }
182    default:
183      NOTREACHED() << "Unexpected notification type in InstantService.";
184  }
185}
186