blob: dde5d398204ab84d1542e0cd87d4cfd8ee3bd9cd [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/search/search_ipc_router.h"
#include <utility>
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/instant_service.h"
#include "chrome/browser/search/instant_service_factory.h"
#include "chrome/browser/search/search.h"
#include "chrome/common/render_messages.h"
#include "components/search/search.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace {
bool IsInInstantProcess(content::RenderFrameHost* render_frame) {
content::RenderProcessHost* process_host = render_frame->GetProcess();
const InstantService* instant_service = InstantServiceFactory::GetForProfile(
Profile::FromBrowserContext(process_host->GetBrowserContext()));
if (!instant_service)
return false;
return instant_service->IsInstantProcess(process_host->GetID());
}
class EmbeddedSearchClientFactoryImpl
: public SearchIPCRouter::EmbeddedSearchClientFactory,
public chrome::mojom::EmbeddedSearchConnector {
public:
// |web_contents| and |binding| must outlive this object.
EmbeddedSearchClientFactoryImpl(
content::WebContents* web_contents,
mojo::AssociatedBinding<chrome::mojom::EmbeddedSearch>* binding)
: client_binding_(binding), factory_bindings_(web_contents, this) {
DCHECK(web_contents);
DCHECK(binding);
// Before we are connected to a frame we throw away all messages.
mojo::MakeRequestAssociatedWithDedicatedPipe(&embedded_search_client_);
}
chrome::mojom::EmbeddedSearchClient* GetEmbeddedSearchClient() override {
return embedded_search_client_.get();
}
private:
void Connect(
chrome::mojom::EmbeddedSearchAssociatedRequest request,
chrome::mojom::EmbeddedSearchClientAssociatedPtrInfo client) override;
// An interface used to push updates to the frame that connected to us. Before
// we've been connected to a frame, messages sent on this interface go into
// the void.
chrome::mojom::EmbeddedSearchClientAssociatedPtr embedded_search_client_;
// Used to bind incoming interface requests to the implementation, which lives
// in SearchIPCRouter.
mojo::AssociatedBinding<chrome::mojom::EmbeddedSearch>* client_binding_;
// Binding used to listen to connection requests.
content::WebContentsFrameBindingSet<chrome::mojom::EmbeddedSearchConnector>
factory_bindings_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedSearchClientFactoryImpl);
};
void EmbeddedSearchClientFactoryImpl::Connect(
chrome::mojom::EmbeddedSearchAssociatedRequest request,
chrome::mojom::EmbeddedSearchClientAssociatedPtrInfo client) {
content::RenderFrameHost* frame = factory_bindings_.GetCurrentTargetFrame();
const bool is_main_frame = frame->GetParent() == nullptr;
if (!IsInInstantProcess(frame) || !is_main_frame) {
return;
}
client_binding_->Bind(std::move(request));
embedded_search_client_.Bind(std::move(client));
}
} // namespace
SearchIPCRouter::SearchIPCRouter(content::WebContents* web_contents,
Delegate* delegate,
std::unique_ptr<Policy> policy)
: WebContentsObserver(web_contents),
delegate_(delegate),
policy_(std::move(policy)),
commit_counter_(0),
is_active_tab_(false),
binding_(this),
embedded_search_client_factory_(
new EmbeddedSearchClientFactoryImpl(web_contents, &binding_)) {
DCHECK(web_contents);
DCHECK(delegate);
DCHECK(policy_.get());
}
SearchIPCRouter::~SearchIPCRouter() = default;
void SearchIPCRouter::OnNavigationEntryCommitted() {
++commit_counter_;
embedded_search_client()->SetPageSequenceNumber(commit_counter_);
}
void SearchIPCRouter::SetInputInProgress(bool input_in_progress) {
if (!policy_->ShouldSendSetInputInProgress(is_active_tab_))
return;
embedded_search_client()->SetInputInProgress(input_in_progress);
}
void SearchIPCRouter::OmniboxFocusChanged(OmniboxFocusState state,
OmniboxFocusChangeReason reason) {
if (!policy_->ShouldSendOmniboxFocusChanged())
return;
embedded_search_client()->FocusChanged(state, reason);
}
void SearchIPCRouter::SendMostVisitedItems(
const std::vector<InstantMostVisitedItem>& items,
bool is_custom_links) {
if (!policy_->ShouldSendMostVisitedItems())
return;
embedded_search_client()->MostVisitedChanged(items, is_custom_links);
}
void SearchIPCRouter::SendThemeBackgroundInfo(
const ThemeBackgroundInfo& theme_info) {
if (!policy_->ShouldSendThemeBackgroundInfo())
return;
embedded_search_client()->ThemeChanged(theme_info);
}
void SearchIPCRouter::OnTabActivated() {
is_active_tab_ = true;
}
void SearchIPCRouter::OnTabDeactivated() {
is_active_tab_ = false;
}
void SearchIPCRouter::FocusOmnibox(int page_seq_no, bool focus) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessFocusOmnibox(is_active_tab_))
return;
delegate_->FocusOmnibox(focus);
}
void SearchIPCRouter::DeleteMostVisitedItem(int page_seq_no, const GURL& url) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessDeleteMostVisitedItem())
return;
delegate_->OnDeleteMostVisitedItem(url);
}
void SearchIPCRouter::UndoMostVisitedDeletion(int page_seq_no,
const GURL& url) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessUndoMostVisitedDeletion())
return;
delegate_->OnUndoMostVisitedDeletion(url);
}
void SearchIPCRouter::UndoAllMostVisitedDeletions(int page_seq_no) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessUndoAllMostVisitedDeletions())
return;
delegate_->OnUndoAllMostVisitedDeletions();
}
void SearchIPCRouter::ToggleMostVisitedOrCustomLinks(int page_seq_no) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessToggleMostVisitedOrCustomLinks())
return;
delegate_->OnToggleMostVisitedOrCustomLinks();
}
void SearchIPCRouter::AddCustomLink(int page_seq_no,
const GURL& url,
const std::string& title,
AddCustomLinkCallback callback) {
bool result = false;
if (page_seq_no == commit_counter_ && policy_->ShouldProcessAddCustomLink()) {
result = delegate_->OnAddCustomLink(url, title);
}
std::move(callback).Run(result);
}
void SearchIPCRouter::UpdateCustomLink(int page_seq_no,
const GURL& url,
const GURL& new_url,
const std::string& new_title,
UpdateCustomLinkCallback callback) {
bool result = false;
if (page_seq_no == commit_counter_ &&
policy_->ShouldProcessUpdateCustomLink()) {
result = delegate_->OnUpdateCustomLink(url, new_url, new_title);
}
std::move(callback).Run(result);
}
void SearchIPCRouter::ReorderCustomLink(int page_seq_no,
const GURL& url,
int new_pos) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessReorderCustomLink())
return;
delegate_->OnReorderCustomLink(url, new_pos);
}
void SearchIPCRouter::DeleteCustomLink(int page_seq_no,
const GURL& url,
DeleteCustomLinkCallback callback) {
bool result = false;
if (page_seq_no == commit_counter_ &&
policy_->ShouldProcessDeleteCustomLink()) {
result = delegate_->OnDeleteCustomLink(url);
}
std::move(callback).Run(result);
}
void SearchIPCRouter::UndoCustomLinkAction(int page_seq_no) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessUndoCustomLinkAction())
return;
delegate_->OnUndoCustomLinkAction();
}
void SearchIPCRouter::ResetCustomLinks(int page_seq_no) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessResetCustomLinks())
return;
delegate_->OnResetCustomLinks();
}
void SearchIPCRouter::LogEvent(int page_seq_no,
NTPLoggingEventType event,
base::TimeDelta time) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessLogEvent())
return;
delegate_->OnLogEvent(event, time);
}
void SearchIPCRouter::LogSuggestionEventWithValue(
int page_seq_no,
NTPSuggestionsLoggingEventType event,
int data,
base::TimeDelta time) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessLogSuggestionEventWithValue())
return;
delegate_->OnLogSuggestionEventWithValue(event, data, time);
}
void SearchIPCRouter::LogMostVisitedImpression(
int page_seq_no,
const ntp_tiles::NTPTileImpression& impression) {
if (page_seq_no != commit_counter_)
return;
// Logging impressions is controlled by the same policy as logging events.
if (!policy_->ShouldProcessLogEvent())
return;
delegate_->OnLogMostVisitedImpression(impression);
}
void SearchIPCRouter::LogMostVisitedNavigation(
int page_seq_no,
const ntp_tiles::NTPTileImpression& impression) {
if (page_seq_no != commit_counter_)
return;
// Logging navigations is controlled by the same policy as logging events.
if (!policy_->ShouldProcessLogEvent())
return;
delegate_->OnLogMostVisitedNavigation(impression);
}
void SearchIPCRouter::PasteAndOpenDropdown(int page_seq_no,
const base::string16& text) {
if (page_seq_no != commit_counter_)
return;
if (!policy_->ShouldProcessPasteIntoOmnibox(is_active_tab_))
return;
delegate_->PasteIntoOmnibox(text);
}
void SearchIPCRouter::SetCustomBackgroundURL(const GURL& url) {
if (!policy_->ShouldProcessSetCustomBackgroundURL())
return;
delegate_->OnSetCustomBackgroundURL(url);
}
void SearchIPCRouter::SetCustomBackgroundURLWithAttributions(
const GURL& background_url,
const std::string& attribution_line_1,
const std::string& attribution_line_2,
const GURL& action_url) {
if (!policy_->ShouldProcessSetCustomBackgroundURLWithAttributions())
return;
delegate_->OnSetCustomBackgroundURLWithAttributions(
background_url, attribution_line_1, attribution_line_2, action_url);
}
void SearchIPCRouter::SelectLocalBackgroundImage() {
if (!policy_->ShouldProcessSelectLocalBackgroundImage())
return;
delegate_->OnSelectLocalBackgroundImage();
}
void SearchIPCRouter::BlocklistSearchSuggestion(int32_t task_version,
int64_t task_id) {
if (!policy_->ShouldProcessBlocklistSearchSuggestion())
return;
delegate_->OnBlocklistSearchSuggestion(task_version, task_id);
}
void SearchIPCRouter::BlocklistSearchSuggestionWithHash(
int32_t task_version,
int64_t task_id,
const std::vector<uint8_t>& hash) {
if (!policy_->ShouldProcessBlocklistSearchSuggestionWithHash())
return;
if (hash.size() > 4) {
return;
}
delegate_->OnBlocklistSearchSuggestionWithHash(task_version, task_id,
hash.data());
}
void SearchIPCRouter::SearchSuggestionSelected(
int32_t task_version,
int64_t task_id,
const std::vector<uint8_t>& hash) {
if (!policy_->ShouldProcessSearchSuggestionSelected())
return;
if (hash.size() > 4) {
return;
}
delegate_->OnSearchSuggestionSelected(task_version, task_id, hash.data());
}
void SearchIPCRouter::OptOutOfSearchSuggestions() {
if (!policy_->ShouldProcessOptOutOfSearchSuggestions())
return;
delegate_->OnOptOutOfSearchSuggestions();
}
void SearchIPCRouter::set_delegate_for_testing(Delegate* delegate) {
DCHECK(delegate);
delegate_ = delegate;
}
void SearchIPCRouter::set_policy_for_testing(std::unique_ptr<Policy> policy) {
DCHECK(policy);
policy_ = std::move(policy);
}