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/ui/search/search_ipc_router.h"
6
7#include "chrome/browser/profiles/profile.h"
8#include "chrome/browser/search/search.h"
9#include "chrome/common/render_messages.h"
10#include "content/public/browser/navigation_details.h"
11#include "content/public/browser/web_contents.h"
12
13namespace {
14
15bool IsProviderValid(const base::string16& provider) {
16  // Only allow string of 8 alphanumeric characters or less as providers.
17  // The empty string is considered valid and should be treated as if no
18  // provider were specified.
19  if (provider.length() > 8)
20    return false;
21  for (base::string16::const_iterator it = provider.begin();
22       it != provider.end(); ++it) {
23    if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it))
24      return false;
25  }
26  return true;
27}
28
29}  // namespace
30
31SearchIPCRouter::SearchIPCRouter(content::WebContents* web_contents,
32                                 Delegate* delegate, scoped_ptr<Policy> policy)
33    : WebContentsObserver(web_contents),
34      delegate_(delegate),
35      policy_(policy.Pass()),
36      commit_counter_(0),
37      is_active_tab_(false) {
38  DCHECK(web_contents);
39  DCHECK(delegate);
40  DCHECK(policy_.get());
41}
42
43SearchIPCRouter::~SearchIPCRouter() {}
44
45void SearchIPCRouter::OnNavigationEntryCommitted() {
46  ++commit_counter_;
47  Send(new ChromeViewMsg_SetPageSequenceNumber(routing_id(), commit_counter_));
48}
49
50void SearchIPCRouter::DetermineIfPageSupportsInstant() {
51  Send(new ChromeViewMsg_DetermineIfPageSupportsInstant(routing_id()));
52}
53
54void SearchIPCRouter::SendChromeIdentityCheckResult(
55    const base::string16& identity,
56    bool identity_match) {
57  if (!policy_->ShouldProcessChromeIdentityCheck())
58    return;
59
60  Send(new ChromeViewMsg_ChromeIdentityCheckResult(routing_id(), identity,
61                                                   identity_match));
62}
63
64void SearchIPCRouter::SetPromoInformation(bool is_app_launcher_enabled) {
65  if (!policy_->ShouldSendSetPromoInformation())
66    return;
67
68  Send(new ChromeViewMsg_SearchBoxPromoInformation(routing_id(),
69                                                   is_app_launcher_enabled));
70}
71
72void SearchIPCRouter::SetDisplayInstantResults() {
73  if (!policy_->ShouldSendSetDisplayInstantResults())
74    return;
75
76  bool is_search_results_page = !chrome::GetSearchTerms(web_contents()).empty();
77  bool display_instant_results = is_search_results_page ?
78      chrome::ShouldPrefetchSearchResultsOnSRP() :
79          chrome::ShouldPrefetchSearchResults();
80  Send(new ChromeViewMsg_SearchBoxSetDisplayInstantResults(
81       routing_id(), display_instant_results));
82}
83
84void SearchIPCRouter::SetSuggestionToPrefetch(
85    const InstantSuggestion& suggestion) {
86  if (!policy_->ShouldSendSetSuggestionToPrefetch())
87    return;
88
89  Send(new ChromeViewMsg_SearchBoxSetSuggestionToPrefetch(routing_id(),
90                                                          suggestion));
91}
92
93void SearchIPCRouter::SetOmniboxStartMargin(int start_margin) {
94  if (!policy_->ShouldSendSetOmniboxStartMargin())
95    return;
96
97  Send(new ChromeViewMsg_SearchBoxMarginChange(routing_id(), start_margin));
98}
99
100void SearchIPCRouter::SetInputInProgress(bool input_in_progress) {
101  if (!policy_->ShouldSendSetInputInProgress(is_active_tab_))
102    return;
103
104  Send(new ChromeViewMsg_SearchBoxSetInputInProgress(routing_id(),
105                                                     input_in_progress));
106}
107
108void SearchIPCRouter::OmniboxFocusChanged(OmniboxFocusState state,
109                                          OmniboxFocusChangeReason reason) {
110  if (!policy_->ShouldSendOmniboxFocusChanged())
111    return;
112
113  Send(new ChromeViewMsg_SearchBoxFocusChanged(routing_id(), state, reason));
114}
115
116void SearchIPCRouter::SendMostVisitedItems(
117    const std::vector<InstantMostVisitedItem>& items) {
118  if (!policy_->ShouldSendMostVisitedItems())
119    return;
120
121  Send(new ChromeViewMsg_SearchBoxMostVisitedItemsChanged(routing_id(), items));
122}
123
124void SearchIPCRouter::SendThemeBackgroundInfo(
125    const ThemeBackgroundInfo& theme_info) {
126  if (!policy_->ShouldSendThemeBackgroundInfo())
127    return;
128
129  Send(new ChromeViewMsg_SearchBoxThemeChanged(routing_id(), theme_info));
130}
131
132void SearchIPCRouter::ToggleVoiceSearch() {
133  if (!policy_->ShouldSendToggleVoiceSearch())
134    return;
135
136  Send(new ChromeViewMsg_SearchBoxToggleVoiceSearch(routing_id()));
137}
138
139void SearchIPCRouter::Submit(const base::string16& text) {
140  if (!policy_->ShouldSubmitQuery())
141    return;
142
143  Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text));
144}
145
146void SearchIPCRouter::OnTabActivated() {
147  is_active_tab_ = true;
148}
149
150void SearchIPCRouter::OnTabDeactivated() {
151  is_active_tab_ = false;
152}
153
154bool SearchIPCRouter::OnMessageReceived(const IPC::Message& message) {
155  Profile* profile =
156      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
157  if (!chrome::IsRenderedInInstantProcess(web_contents(), profile))
158    return false;
159
160  bool handled = true;
161  IPC_BEGIN_MESSAGE_MAP(SearchIPCRouter, message)
162    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_InstantSupportDetermined,
163                        OnInstantSupportDetermined)
164    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetVoiceSearchSupported,
165                        OnVoiceSearchSupportDetermined)
166    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusOmnibox, OnFocusOmnibox);
167    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxNavigate,
168                        OnSearchBoxNavigate);
169    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem,
170                        OnDeleteMostVisitedItem);
171    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion,
172                        OnUndoMostVisitedDeletion);
173    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions,
174                        OnUndoAllMostVisitedDeletions);
175    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogEvent, OnLogEvent);
176    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogMostVisitedImpression,
177                        OnLogMostVisitedImpression);
178    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogMostVisitedNavigation,
179                        OnLogMostVisitedNavigation);
180    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PasteAndOpenDropdown,
181                        OnPasteAndOpenDropDown);
182    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ChromeIdentityCheck,
183                        OnChromeIdentityCheck);
184    IPC_MESSAGE_UNHANDLED(handled = false)
185  IPC_END_MESSAGE_MAP()
186  return handled;
187}
188
189void SearchIPCRouter::OnInstantSupportDetermined(int page_seq_no,
190                                                 bool instant_support) const {
191  if (page_seq_no != commit_counter_)
192    return;
193
194  delegate_->OnInstantSupportDetermined(instant_support);
195}
196
197void SearchIPCRouter::OnVoiceSearchSupportDetermined(
198    int page_seq_no,
199    bool supports_voice_search) const {
200  if (page_seq_no != commit_counter_)
201    return;
202
203  delegate_->OnInstantSupportDetermined(true);
204  if (!policy_->ShouldProcessSetVoiceSearchSupport())
205    return;
206
207  delegate_->OnSetVoiceSearchSupport(supports_voice_search);
208}
209
210void SearchIPCRouter::OnFocusOmnibox(int page_seq_no,
211                                     OmniboxFocusState state) const {
212  if (page_seq_no != commit_counter_)
213    return;
214
215  delegate_->OnInstantSupportDetermined(true);
216  if (!policy_->ShouldProcessFocusOmnibox(is_active_tab_))
217    return;
218
219  delegate_->FocusOmnibox(state);
220}
221
222void SearchIPCRouter::OnSearchBoxNavigate(
223    int page_seq_no,
224    const GURL& url,
225    WindowOpenDisposition disposition,
226    bool is_most_visited_item_url) const {
227  if (page_seq_no != commit_counter_)
228    return;
229
230  delegate_->OnInstantSupportDetermined(true);
231  if (!policy_->ShouldProcessNavigateToURL(is_active_tab_))
232    return;
233
234  delegate_->NavigateToURL(url, disposition, is_most_visited_item_url);
235}
236
237void SearchIPCRouter::OnDeleteMostVisitedItem(int page_seq_no,
238                                              const GURL& url) const {
239  if (page_seq_no != commit_counter_)
240    return;
241
242  delegate_->OnInstantSupportDetermined(true);
243  if (!policy_->ShouldProcessDeleteMostVisitedItem())
244    return;
245
246  delegate_->OnDeleteMostVisitedItem(url);
247}
248
249void SearchIPCRouter::OnUndoMostVisitedDeletion(int page_seq_no,
250                                                const GURL& url) const {
251  if (page_seq_no != commit_counter_)
252    return;
253
254  delegate_->OnInstantSupportDetermined(true);
255  if (!policy_->ShouldProcessUndoMostVisitedDeletion())
256    return;
257
258  delegate_->OnUndoMostVisitedDeletion(url);
259}
260
261void SearchIPCRouter::OnUndoAllMostVisitedDeletions(int page_seq_no) const {
262  if (page_seq_no != commit_counter_)
263    return;
264
265  delegate_->OnInstantSupportDetermined(true);
266  if (!policy_->ShouldProcessUndoAllMostVisitedDeletions())
267    return;
268
269  delegate_->OnUndoAllMostVisitedDeletions();
270}
271
272void SearchIPCRouter::OnLogEvent(int page_seq_no,
273                                 NTPLoggingEventType event) const {
274  if (page_seq_no != commit_counter_)
275    return;
276
277  delegate_->OnInstantSupportDetermined(true);
278  if (!policy_->ShouldProcessLogEvent())
279    return;
280
281  delegate_->OnLogEvent(event);
282}
283
284void SearchIPCRouter::OnLogMostVisitedImpression(
285    int page_seq_no, int position, const base::string16& provider) const {
286  if (page_seq_no != commit_counter_ || !IsProviderValid(provider))
287    return;
288
289  delegate_->OnInstantSupportDetermined(true);
290  // Logging impressions is controlled by the same policy as logging events.
291  if (!policy_->ShouldProcessLogEvent())
292    return;
293
294  delegate_->OnLogMostVisitedImpression(position, provider);
295}
296
297void SearchIPCRouter::OnLogMostVisitedNavigation(
298    int page_seq_no, int position, const base::string16& provider) const {
299  if (page_seq_no != commit_counter_ || !IsProviderValid(provider))
300    return;
301
302  delegate_->OnInstantSupportDetermined(true);
303  // Logging navigations is controlled by the same policy as logging events.
304  if (!policy_->ShouldProcessLogEvent())
305    return;
306
307  delegate_->OnLogMostVisitedNavigation(position, provider);
308}
309
310void SearchIPCRouter::OnPasteAndOpenDropDown(int page_seq_no,
311                                             const base::string16& text) const {
312  if (page_seq_no != commit_counter_)
313    return;
314
315  delegate_->OnInstantSupportDetermined(true);
316  if (!policy_->ShouldProcessPasteIntoOmnibox(is_active_tab_))
317    return;
318
319  delegate_->PasteIntoOmnibox(text);
320}
321
322void SearchIPCRouter::OnChromeIdentityCheck(
323    int page_seq_no,
324    const base::string16& identity) const {
325  if (page_seq_no != commit_counter_)
326    return;
327
328  delegate_->OnInstantSupportDetermined(true);
329  if (!policy_->ShouldProcessChromeIdentityCheck())
330    return;
331
332  delegate_->OnChromeIdentityCheck(identity);
333}
334
335void SearchIPCRouter::set_delegate_for_testing(Delegate* delegate) {
336  DCHECK(delegate);
337  delegate_ = delegate;
338}
339
340void SearchIPCRouter::set_policy_for_testing(scoped_ptr<Policy> policy) {
341  DCHECK(policy.get());
342  policy_.reset(policy.release());
343}
344