| Index: components/contextual_suggestions/contextual_suggestions_service.cc
|
| diff --git a/components/contextual_suggestions/contextual_suggestions_service.cc b/components/contextual_suggestions/contextual_suggestions_service.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3d393046db416726ece3f874152d950613cc2c14
|
| --- /dev/null
|
| +++ b/components/contextual_suggestions/contextual_suggestions_service.cc
|
| @@ -0,0 +1,193 @@
|
| +// Copyright 2017 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 "components/contextual_suggestions/contextual_suggestions_service.h"
|
| +
|
| +#include "base/feature_list.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/metrics/field_trial_params.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "components/contextual_suggestions/features.h"
|
| +#include "components/data_use_measurement/core/data_use_user_data.h"
|
| +#include "components/variations/net/variations_http_headers.h"
|
| +#include "google_apis/gaia/gaia_constants.h"
|
| +#include "net/base/escape.h"
|
| +#include "net/base/load_flags.h"
|
| +#include "net/http/http_response_headers.h"
|
| +#include "net/traffic_annotation/network_traffic_annotation.h"
|
| +#include "net/url_request/url_fetcher.h"
|
| +
|
| +namespace contextual_suggestions {
|
| +
|
| +namespace {
|
| +
|
| +// Parameter names used by the experiment redirecting Zero Suggestion requests
|
| +// to a service provided by the Chrome team
|
| +const char kZeroSuggestRedirectToChromeServerAddressParam[] =
|
| + "ZeroSuggestRedirectToChromeServerAddress";
|
| +const char kZeroSuggestRedirectToChromeAdditionalFieldsParam[] =
|
| + "ZeroSuggestRedirectToChromeAdditionalFields";
|
| +
|
| +// Format string for OAuth2 authentication headers.
|
| +const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
|
| +
|
| +} // namespace
|
| +
|
| +ContextualSuggestionsService::ContextualSuggestionsService(
|
| + SigninManagerBase* signin_manager,
|
| + OAuth2TokenService* token_service,
|
| + TemplateURLService* template_url_service,
|
| + net::URLRequestContextGetter* request_context)
|
| + : request_context_(request_context),
|
| + signin_manager_(signin_manager),
|
| + template_url_service_(template_url_service),
|
| + token_service_(token_service) {}
|
| +
|
| +ContextualSuggestionsService::~ContextualSuggestionsService() {}
|
| +
|
| +bool ContextualSuggestionsService::UseExperimentalZeroSuggestSuggestions()
|
| + const {
|
| + if (!base::FeatureList::IsEnabled(kZeroSuggestRedirectToChrome) ||
|
| + template_url_service_ == nullptr) {
|
| + return false;
|
| + }
|
| +
|
| + // Check that the default search engine is Google.
|
| + const TemplateURL& default_provider_url =
|
| + *template_url_service_->GetDefaultSearchProvider();
|
| + const SearchTermsData& search_terms_data =
|
| + template_url_service_->search_terms_data();
|
| + if (default_provider_url.GetEngineType(search_terms_data) !=
|
| + SEARCH_ENGINE_GOOGLE) {
|
| + return false;
|
| + }
|
| +
|
| + // Check that the suggest URL for redirect to chrome field trial is valid.
|
| + const GURL suggest_url =
|
| + ExperimentalZeroSuggestURL(/*visited_url=*/std::string());
|
| + if (!suggest_url.is_valid()) {
|
| + return false;
|
| + }
|
| +
|
| + // Check that the suggest URL for redirect to chrome is HTTPS.
|
| + return suggest_url.SchemeIsCryptographic();
|
| +}
|
| +
|
| +void ContextualSuggestionsService::CreateContextualSuggestionsRequest(
|
| + const std::string& visited_url,
|
| + net::URLFetcherDelegate* fetcher_delegate,
|
| + ContextualSuggestionsCallback callback) {
|
| + DCHECK(signin_manager_);
|
| + DCHECK(token_service_);
|
| +
|
| + // Skip this request if still waiting for oauth2 token.
|
| + if (token_fetcher_) {
|
| + std::move(callback).Run(nullptr);
|
| + return;
|
| + }
|
| +
|
| + std::unique_ptr<net::URLFetcher> fetcher =
|
| + CreateRequest(visited_url, fetcher_delegate);
|
| + if (fetcher == nullptr) {
|
| + std::move(callback).Run(nullptr);
|
| + return;
|
| + }
|
| +
|
| + // Create the oauth2 token fetcher.
|
| + OAuth2TokenService::ScopeSet scopes{GaiaConstants::kAnyApiOAuth2Scope};
|
| + token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
|
| + "contextual_suggestions_service", signin_manager_, token_service_, scopes,
|
| + base::BindOnce(&ContextualSuggestionsService::AccessTokenAvailable,
|
| + base::Unretained(this), std::move(fetcher),
|
| + std::move(callback)));
|
| +}
|
| +
|
| +// static
|
| +GURL ContextualSuggestionsService::ExperimentalZeroSuggestURL(
|
| + const std::string& visited_url) {
|
| + const std::string server_address = base::GetFieldTrialParamValueByFeature(
|
| + kZeroSuggestRedirectToChrome,
|
| + kZeroSuggestRedirectToChromeServerAddressParam);
|
| + const std::string additional_parameters =
|
| + base::GetFieldTrialParamValueByFeature(
|
| + kZeroSuggestRedirectToChrome,
|
| + kZeroSuggestRedirectToChromeAdditionalFieldsParam);
|
| + return GURL(server_address + "/url=" + net::EscapePath(visited_url) +
|
| + additional_parameters);
|
| +}
|
| +
|
| +std::unique_ptr<net::URLFetcher> ContextualSuggestionsService::CreateRequest(
|
| + const std::string& visited_url,
|
| + net::URLFetcherDelegate* fetcher_delegate) const {
|
| + net::NetworkTrafficAnnotationTag traffic_annotation =
|
| + net::DefineNetworkTrafficAnnotation("omnibox_contextual_zerosuggest", R"(
|
| + semantics {
|
| + sender: "Omnibox"
|
| + description:
|
| + "When the user focuses the omnibox, Chrome can provide search or "
|
| + "navigation suggestions from the default search provider in the "
|
| + "omnibox dropdown, based on the current page URL.\n"
|
| + "This is limited to users whose default search engine is Google, "
|
| + "as no other search engines currently support this kind of "
|
| + "suggestion."
|
| + trigger: "The omnibox receives focus."
|
| + data: "The URL of the current page."
|
| + destination: GOOGLE_OWNED_SERVICE
|
| + }
|
| + policy {
|
| + cookies_allowed: false
|
| + setting:
|
| + "Users can control this feature via the 'Use a prediction service "
|
| + "to help complete searches and URLs typed in the address bar' "
|
| + "settings under 'Privacy'. The feature is enabled by default."
|
| + chrome_policy {
|
| + SearchSuggestEnabled {
|
| + policy_options {mode: MANDATORY}
|
| + SearchSuggestEnabled: false
|
| + }
|
| + }
|
| + })");
|
| + const int kFetcherID = 1;
|
| + const GURL suggest_url = ExperimentalZeroSuggestURL(visited_url);
|
| + DCHECK(!suggest_url.is_valid());
|
| +
|
| + std::unique_ptr<net::URLFetcher> fetcher =
|
| + net::URLFetcher::Create(kFetcherID, suggest_url, net::URLFetcher::GET,
|
| + fetcher_delegate, traffic_annotation);
|
| + data_use_measurement::DataUseUserData::AttachToFetcher(
|
| + fetcher.get(), data_use_measurement::DataUseUserData::OMNIBOX);
|
| + fetcher->SetRequestContext(request_context_);
|
| + fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
|
| + // Add Chrome experiment state to the request headers.
|
| + net::HttpRequestHeaders headers;
|
| + // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does
|
| + // not affect transmission of experiments coming from the variations server.
|
| + variations::AppendVariationHeaders(fetcher->GetOriginalURL(),
|
| + /*incognito=*/false,
|
| + /*uma_enabled=*/false,
|
| + /*is_signed_in=*/false, &headers);
|
| + fetcher->SetExtraRequestHeaders(headers.ToString());
|
| + return fetcher;
|
| +}
|
| +
|
| +void ContextualSuggestionsService::AccessTokenAvailable(
|
| + std::unique_ptr<net::URLFetcher> fetcher,
|
| + ContextualSuggestionsCallback callback,
|
| + const GoogleServiceAuthError& error,
|
| + const std::string& access_token) {
|
| + DCHECK(token_fetcher_);
|
| + std::unique_ptr<AccessTokenFetcher> token_fetcher_deleter(
|
| + std::move(token_fetcher_));
|
| +
|
| + if (error.state() != GoogleServiceAuthError::NONE) {
|
| + std::move(callback).Run(nullptr);
|
| + return;
|
| + }
|
| + DCHECK(!access_token.empty());
|
| + fetcher->AddExtraRequestHeader(
|
| + base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
|
| + std::move(callback).Run(std::move(fetcher));
|
| +}
|
| +
|
| +} // namespace contextual_suggestions
|
|
|