Commit e5e8e623 authored by Mei Liang's avatar Mei Liang Committed by Commit Bot

Add a component, JourneyInfoFetch, for fetching SwitcherJourney info

This CL adds a component, namely JourneyInfoFetcher, to talk with the
Memex endpoint server. The JourneyInfoFetcher makes a request
to the server and gets a SwitcherJourney response in json format.
Then JourneyInfoFetcher parses the response accordingly
to create a list of pageloads for the given callback.

Bug: 853290
Change-Id: If31982dac57fbb795f72c09cc8914cfaa6b49bdb
Reviewed-on: https://chromium-review.googlesource.com/c/1155719
Commit-Queue: Mei Liang <meiliang@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Reviewed-by: default avatarNick Harper <nharper@chromium.org>
Reviewed-by: default avatarColin Blundell <blundell@chromium.org>
Reviewed-by: default avatarChristian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608319}
parent e0fb41b1
...@@ -298,6 +298,7 @@ group("gn_all") { ...@@ -298,6 +298,7 @@ group("gn_all") {
"//chrome/android/webapk/shell_apk:webapk", "//chrome/android/webapk/shell_apk:webapk",
"//chrome/test/vr/perf:motopho_latency_test", "//chrome/test/vr/perf:motopho_latency_test",
"//components/invalidation/impl:components_invalidation_impl_junit_tests", "//components/invalidation/impl:components_invalidation_impl_junit_tests",
"//components/journey:journey_info_fetcher",
"//components/policy/android:components_policy_junit_tests", "//components/policy/android:components_policy_junit_tests",
"//components/signin/core/browser/android:components_signin_junit_tests", "//components/signin/core/browser/android:components_signin_junit_tests",
"//content/public/android:content_junit_tests", "//content/public/android:content_junit_tests",
......
...@@ -221,6 +221,7 @@ test("components_unittests") { ...@@ -221,6 +221,7 @@ test("components_unittests") {
"//components/history/content/browser:unit_tests", "//components/history/content/browser:unit_tests",
"//components/invalidation/impl:unit_tests", "//components/invalidation/impl:unit_tests",
"//components/invalidation/public:unit_tests", "//components/invalidation/public:unit_tests",
"//components/journey:unit_tests",
"//components/keyed_service/content:unit_tests", "//components/keyed_service/content:unit_tests",
"//components/language/content/browser:unit_tests", "//components/language/content/browser:unit_tests",
"//components/link_header_util:unit_tests", "//components/link_header_util:unit_tests",
......
# Copyright 2018 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.
static_library("journey_info_fetcher") {
sources = [
"journey_info_fetcher.cc",
"journey_info_fetcher.h",
"journey_info_json_request.cc",
"journey_info_json_request.h",
]
deps = [
"//base",
"//components/journey/proto",
"//components/variations/net:net",
"//net",
"//services/data_decoder/public/cpp",
"//services/identity/public/cpp",
"//services/network/public/cpp",
"//url",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"journey_info_fetcher_unittest.cc",
]
deps = [
":journey_info_fetcher",
"//base/test:test_support",
"//services/data_decoder/public/cpp:test_support",
"//services/identity/public/cpp:test_support",
"//services/network:test_support",
"//testing/gmock",
"//testing/gtest",
]
}
include_rules = [
"+base",
"+components",
"+net",
"+services/data_decoder/public/cpp",
"+services/identity/public/cpp",
"+services/network/public/cpp",
"+services/network/test",
"+url",
]
acolwell@chromium.org
wychen@chromium.org
yusufo@chromium.org
# Overview
This component deals with multiple tabs or pages navigation that starts with an
explicit user action, and has similar context. The component contains tools to
process these navigations and present them in a way that provides users a
smoother UI flow within their tabs.
# Understanding Terms
This component introduces several terms, include:
* Pageload: A load of a page by a given user at a moment in time, and they are
derived from the user's Chrome History data.
* User Journey: A set of connected pageloads that are determined based on an
explicit user action, such as omnibox search, and the semantic relationship
with others.
# Provisions
This component provides a `JourneyInfoFetcher`, an authenticated fetcher that
fetches a list of pageload information in a json format from the user journey
endpoint server. This fetcher can be used by any client that needs access to
these information from the server.
// Copyright 2018 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/journey/journey_info_fetcher.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "components/journey/journey_info_json_request.h"
#include "services/data_decoder/public/cpp/safe_json_parser.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace journey {
namespace {
const char kChromeSyncScope[] = "https://www.googleapis.com/auth/chromememex";
} // namespace
JourneyInfoFetcher::JourneyInfoFetcher(
identity::IdentityManager* identity_manager,
const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory)
: identity_manager_(identity_manager), loader_factory_(loader_factory) {}
JourneyInfoFetcher::~JourneyInfoFetcher() = default;
void JourneyInfoFetcher::FetchJourneyInfo(
std::vector<int64_t> timestamps,
FetchResponseAvailableCallback callback) {
if (!identity_manager_->HasPrimaryAccount()) {
FetchFinished(std::move(callback), /*result=*/nullptr,
"Primary Account is not Available. Sign in is required");
return;
}
pending_requests_.emplace(std::move(timestamps), std::move(callback));
RequestOAuthTokenService();
}
void JourneyInfoFetcher::RequestOAuthTokenService() {
if (token_fetcher_)
return;
OAuth2TokenService::ScopeSet scopes{kChromeSyncScope};
token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
"journey_info", identity_manager_, scopes,
base::BindOnce(&JourneyInfoFetcher::AccessTokenFetchFinished,
base::Unretained(this)),
identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
}
void JourneyInfoFetcher::AccessTokenFetchFinished(
GoogleServiceAuthError error,
identity::AccessTokenInfo access_token_info) {
DCHECK(token_fetcher_);
std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
token_fetcher_deleter(std::move(token_fetcher_));
if (error.state() != GoogleServiceAuthError::NONE) {
AccessTokenError(error);
return;
}
DCHECK(!access_token_info.token.empty());
while (!pending_requests_.empty()) {
std::pair<std::vector<int64_t>, FetchResponseAvailableCallback>
timestamp_and_callback = std::move(pending_requests_.front());
pending_requests_.pop();
StartRequest(timestamp_and_callback.first,
std::move(timestamp_and_callback.second),
access_token_info.token);
}
}
void JourneyInfoFetcher::AccessTokenError(const GoogleServiceAuthError& error) {
DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
DLOG(WARNING) << "JourneyInfoFetcher::AccessTokenError "
"Unable to get token: "
<< error.ToString();
while (!pending_requests_.empty()) {
std::pair<std::vector<int64_t>, FetchResponseAvailableCallback>
timestamp_and_callback = std::move(pending_requests_.front());
pending_requests_.pop();
FetchFinished(std::move(timestamp_and_callback.second), /*result=*/nullptr,
error.ToString());
}
}
void JourneyInfoFetcher::StartRequest(const std::vector<int64_t>& timestamps,
FetchResponseAvailableCallback callback,
const std::string& oauth_access_token) {
JourneyInfoJsonRequest::Builder builder;
builder.SetTimestamps(timestamps)
.SetAuthentication(
base::StringPrintf("bearer %s", oauth_access_token.c_str()))
.SetParseJsonCallback(base::BindRepeating(
&data_decoder::SafeJsonParser::Parse,
/*connector=*/nullptr)); // This is an Android-only component,
// connector is unused on Android.
auto json_request = builder.Build();
JourneyInfoJsonRequest* raw_request = json_request.get();
raw_request->Start(
base::BindOnce(&JourneyInfoFetcher::JsonRequestDone,
base::Unretained(this), std::move(json_request),
std::move(callback)),
loader_factory_);
}
const std::string& JourneyInfoFetcher::GetLastJsonForDebugging() const {
return last_fetch_json_;
}
void JourneyInfoFetcher::JsonRequestDone(
std::unique_ptr<JourneyInfoJsonRequest> request,
FetchResponseAvailableCallback callback,
std::unique_ptr<base::Value> result,
const std::string& error_detail) {
DCHECK(request);
last_fetch_json_ = request->GetResponseString();
FetchFinished(std::move(callback), std::move(result), error_detail);
}
void JourneyInfoFetcher::FetchFinished(FetchResponseAvailableCallback callback,
std::unique_ptr<base::Value> result,
const std::string& error_detail) {
DCHECK((result && !result->is_none()) || error_detail != "");
// Returned |result| can be empty while |error_detail| is "".
std::move(callback).Run(std::move(result), error_detail);
}
} // namespace journey
// Copyright 2018 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.
#ifndef COMPONENTS_JOURNEY_JOURNEY_INFO_FETCHER_H_
#define COMPONENTS_JOURNEY_JOURNEY_INFO_FETCHER_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/containers/queue.h"
#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
namespace base {
class Value;
} // namespace base
namespace identity {
class IdentityManager;
} // namespace identity
namespace network {
class SharedURLLoaderFactory;
} // namespace network
namespace journey {
class JourneyInfoJsonRequest;
using FetchResponseAvailableCallback =
base::OnceCallback<void(std::unique_ptr<base::Value>, const std::string&)>;
// This class is used to fetch SwitcherJourney information from the server.
class JourneyInfoFetcher {
public:
JourneyInfoFetcher(
identity::IdentityManager* identity_manager,
const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory);
~JourneyInfoFetcher();
// This method fetches journey information based on |timestamps|,
// and calls back to |callback| when complete.
// TODO(meiliang): Add a parameter, GURL url, as the fetching url instead of
// hard code the url.
void FetchJourneyInfo(std::vector<int64_t> timestamps,
FetchResponseAvailableCallback callback);
// This method gets last json response as a string.
const std::string& GetLastJsonForDebugging() const;
private:
void RequestOAuthTokenService();
void StartRequest(const std::vector<int64_t>& timestamps,
FetchResponseAvailableCallback callback,
const std::string& oauth_access_token);
void AccessTokenFetchFinished(GoogleServiceAuthError error,
identity::AccessTokenInfo access_token_info);
void AccessTokenError(const GoogleServiceAuthError& error);
void FetchFinished(FetchResponseAvailableCallback callback,
std::unique_ptr<base::Value> result,
const std::string& error_detail);
void JsonRequestDone(std::unique_ptr<JourneyInfoJsonRequest> request,
FetchResponseAvailableCallback callback,
std::unique_ptr<base::Value> result,
const std::string& error_detail);
identity::IdentityManager* identity_manager_;
std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
const scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
std::string last_fetch_json_;
// This queues stores requests that wait for an access token.
base::queue<std::pair<std::vector<int64_t>, FetchResponseAvailableCallback>>
pending_requests_;
DISALLOW_COPY_AND_ASSIGN(JourneyInfoFetcher);
};
} // namespace journey
#endif // COMPONENTS_JOURNEY_JOURNEY_INFO_FETCHER_H_
// Copyright 2018 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/journey/journey_info_fetcher.h"
#include <utility>
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h"
#include "net/http/http_util.h"
#include "services/data_decoder/public/cpp/testing_json_parser.h"
#include "services/identity/public/cpp/identity_test_environment.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
namespace journey {
const char kEmail[] = "foo_email";
const char kJourneyServer[] =
"https://chrome-memex-dev.appspot.com/api/journey_from_pageload";
const char kEmptyErrorString[] = "";
const std::vector<int64_t> kTimestamps = {1532563271195406};
using MockFetchResponseAvailableCallback =
base::MockCallback<FetchResponseAvailableCallback>;
class JourneyInfoFetcherTest : public testing::Test {
protected:
JourneyInfoFetcherTest() {}
~JourneyInfoFetcherTest() override {}
void SetUp() override {
scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
journey_info_fetcher_ = std::make_unique<JourneyInfoFetcher>(
identity_test_env_.identity_manager(), test_shared_loader_factory);
SignIn();
}
void TearDown() override {}
void SignIn() {
identity_test_env_.MakePrimaryAccountAvailable(kEmail);
identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
}
void SignOut() { identity_test_env_.ClearPrimaryAccount(); }
std::string GenerateJsonResponse(const std::vector<int64_t>& timestamps) {
int timestamps_size = timestamps.size();
std::string response_string = R"(
[
{
"status": "STATUS_OK",
"default_autotabs": {
"pageloads": [
{
"title": {
"weight": 1.0,
"title": "foo"
},
"url": "https://foo.com/",
"image": {
"snippet": "PRS_REPRESENTATIVE_IMAGE",
"confidence": 1.0,
"thumbnail_url": "https://foo-png"
},
"timestamp_us": "1532563271195406",
"is_pruned": false
}
],
"selection_type": "SELECTION_TYPE_LEAVES_AND_TAB_AND_TASK"
},
"journey_id": "3021296114337328326",
"source_page_timestamp_usec": [
)";
for (int i = 0; i < timestamps_size; i++) {
response_string += "\"" + base::NumberToString(timestamps[i]) + "\"";
if (i < timestamps_size - 1)
response_string += ", ";
}
response_string += R"(
]
}
]
)";
return response_string;
}
void SetFakeResponse(const GURL& request_url,
const std::string& response_data,
net::HttpStatusCode response_code,
net::Error error) {
network::ResourceResponseHead head;
std::string headers(base::StringPrintf(
"HTTP/1.1 %d %s\nContent-type: application/json\n\n",
static_cast<int>(response_code), GetHttpReasonPhrase(response_code)));
head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
head.mime_type = "application/json";
network::URLLoaderCompletionStatus status(error);
status.decoded_body_length = response_data.size();
test_url_loader_factory_.AddResponse(request_url, head, response_data,
status);
}
void SendAndAwaitResponse(std::vector<int64_t> timestamps) {
journey_info_fetcher()->FetchJourneyInfo(
timestamps, journey_info_available_callback().Get());
base::RunLoop().RunUntilIdle();
}
MockFetchResponseAvailableCallback& journey_info_available_callback() {
return mock_callback_;
}
JourneyInfoFetcher* journey_info_fetcher() {
return journey_info_fetcher_.get();
}
network::TestURLLoaderFactory* test_url_loader_factory() {
return &test_url_loader_factory_;
}
identity::IdentityTestEnvironment& identity_test_env() {
return identity_test_env_;
}
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
identity::IdentityTestEnvironment identity_test_env_;
MockFetchResponseAvailableCallback mock_callback_;
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<JourneyInfoFetcher> journey_info_fetcher_;
DISALLOW_COPY_AND_ASSIGN(JourneyInfoFetcherTest);
};
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfo) {
std::string json_response_string = GenerateJsonResponse(kTimestamps);
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(testing::NotNull(), kEmptyErrorString));
SendAndAwaitResponse(kTimestamps);
EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(),
testing::Eq(json_response_string));
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoOAuthError) {
identity_test_env().SetAutomaticIssueOfAccessTokens(false);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
journey_info_fetcher()->FetchJourneyInfo(
kTimestamps, journey_info_available_callback().Get());
identity_test_env().WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
base::RunLoop().RunUntilIdle();
}
#if !defined(OS_CHROMEOS)
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoUserNotSignedIn) {
SignOut();
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), "");
}
#endif
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoWithNonParsableResponse) {
std::string json_response_string = "[";
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(),
testing::Eq(json_response_string));
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoWithBadJSONResponse) {
std::string json_response_string = "[]";
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(testing::NotNull(), kEmptyErrorString));
SendAndAwaitResponse(kTimestamps);
EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(),
testing::Eq(json_response_string));
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoNetworkError) {
std::string json_response_string = "[]";
SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK,
net::ERR_FAILED);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), "");
}
TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoHttpError) {
std::string json_response_string = "[]";
SetFakeResponse(GURL(kJourneyServer), json_response_string,
net::HTTP_BAD_REQUEST, net::OK);
EXPECT_CALL(journey_info_available_callback(),
Run(_, testing::Ne(kEmptyErrorString)));
SendAndAwaitResponse(kTimestamps);
EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), "");
}
} // namespace journey
// Copyright 2018 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/journey/journey_info_json_request.h"
#include <algorithm>
#include <utility>
#include <vector>
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "components/journey/proto/batch_get_switcher_journey_from_pageload_request.pb.h"
#include "components/variations/net/variations_http_headers.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
namespace journey {
namespace {
const int k5xxRetries = 2;
std::string GetSerializedJourneyRequest(
const std::vector<int64_t>& timestamps) {
BatchGetSwitcherJourneyFromPageloadRequest request;
for (const auto timestamp : timestamps) {
request.add_page_timestamp_usec(timestamp);
}
return request.SerializeAsString();
}
} // namespace
JourneyInfoJsonRequest::JourneyInfoJsonRequest(
const ParseJSONCallback& callback)
: parse_json_callback_(callback), weak_ptr_factory_(this) {}
JourneyInfoJsonRequest::~JourneyInfoJsonRequest() {}
void JourneyInfoJsonRequest::Start(
CompletedCallback callback,
const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory) {
completed_callback_ = std::move(callback);
last_response_string_.clear();
simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
loader_factory.get(),
base::BindOnce(&JourneyInfoJsonRequest::OnSimpleURLLoaderComplete,
base::Unretained(this)));
}
const std::string& JourneyInfoJsonRequest::GetResponseString() const {
return last_response_string_;
}
void JourneyInfoJsonRequest::OnSimpleURLLoaderComplete(
std::unique_ptr<std::string> response_body) {
DCHECK(simple_url_loader_);
int response_code = -1;
if (simple_url_loader_->ResponseInfo() &&
simple_url_loader_->ResponseInfo()->headers) {
response_code =
simple_url_loader_->ResponseInfo()->headers->response_code();
}
int net_error = simple_url_loader_->NetError();
simple_url_loader_.reset();
if (net_error != net::OK) {
std::move(completed_callback_)
.Run(nullptr, base::StringPrintf("Network error code: %d", net_error));
} else if (response_code / 100 != 2) {
std::move(completed_callback_)
.Run(nullptr,
base::StringPrintf("Http response error code: %d", response_code));
} else {
last_response_string_ = std::move(*response_body);
parse_json_callback_.Run(
last_response_string_,
base::BindRepeating(&JourneyInfoJsonRequest::OnJsonParsed,
weak_ptr_factory_.GetWeakPtr()),
base::BindRepeating(&JourneyInfoJsonRequest::OnJsonError,
weak_ptr_factory_.GetWeakPtr()));
}
}
void JourneyInfoJsonRequest::OnJsonParsed(std::unique_ptr<base::Value> result) {
std::move(completed_callback_).Run(std::move(result), std::string());
}
void JourneyInfoJsonRequest::OnJsonError(const std::string& error) {
DLOG(WARNING) << "Received invalid JSON (" << error
<< "): " << last_response_string_;
std::move(completed_callback_).Run(nullptr, error);
}
JourneyInfoJsonRequest::Builder::Builder()
: url_(GURL(
"https://chrome-memex-dev.appspot.com/api/journey_from_pageload")) {}
JourneyInfoJsonRequest::Builder::~Builder() = default;
std::unique_ptr<JourneyInfoJsonRequest> JourneyInfoJsonRequest::Builder::Build()
const {
auto request = std::make_unique<JourneyInfoJsonRequest>(parse_json_callback_);
request->simple_url_loader_ = BuildSimpleURLLoader();
return request;
}
JourneyInfoJsonRequest::Builder&
JourneyInfoJsonRequest::Builder::SetAuthentication(
const std::string& auth_header) {
DVLOG(0) << "Authorization header " << auth_header;
auth_header_ = auth_header;
return *this;
}
JourneyInfoJsonRequest::Builder& JourneyInfoJsonRequest::Builder::SetTimestamps(
const std::vector<int64_t>& timestamps) {
body_ = GetSerializedJourneyRequest(timestamps);
return *this;
}
JourneyInfoJsonRequest::Builder&
JourneyInfoJsonRequest::Builder::SetParseJsonCallback(
ParseJSONCallback callback) {
parse_json_callback_ = std::move(callback);
return *this;
}
net::HttpRequestHeaders
JourneyInfoJsonRequest::Builder::BuildSimpleURLLoaderHeaders() const {
net::HttpRequestHeaders headers;
headers.SetHeader("Content-Type", "application/json; charset=UTF-8");
if (!auth_header_.empty()) {
headers.SetHeader("Authorization", auth_header_);
}
variations::AppendVariationHeaders(url_, variations::InIncognito::kNo,
variations::SignedIn::kNo, &headers);
return headers;
}
std::unique_ptr<network::SimpleURLLoader>
JourneyInfoJsonRequest::Builder::BuildSimpleURLLoader() const {
// TODO(meiliang): update the policy section with correct setting and
// chrome_policy
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("journey_journey_info_json_request",
R"(
semantics {
sender: "Journey info Json request"
description:
"Chromium can show a list of pages that are related to currently "
"visited page."
trigger:
"Triggered at every tab selection, and every 30s has passed since "
"the last request for that journey if there is already a journey "
"to match to the tab."
data:
"Only white-listed signed-in test user's OAuth2 credentials,"
"the task_id or the timestamps of the current tab."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting: "None."
chrome_policy {}
})");
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = GURL(url_);
resource_request->load_flags =
net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES;
resource_request->headers = BuildSimpleURLLoaderHeaders();
resource_request->method = "POST";
auto simple_loader = network::SimpleURLLoader::Create(
std::move(resource_request), traffic_annotation);
simple_loader->SetAllowHttpErrorResults(true);
simple_loader->AttachStringForUpload(body_,
"application/json; charset=UTF-8");
simple_loader->SetRetryOptions(
k5xxRetries, network::SimpleURLLoader::RetryMode::RETRY_ON_5XX);
return simple_loader;
}
} // namespace journey
// Copyright 2018 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.
#ifndef COMPONENTS_JOURNEY_JOURNEY_INFO_JSON_REQUEST_H_
#define COMPONENTS_JOURNEY_JOURNEY_INFO_JSON_REQUEST_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "url/gurl.h"
namespace base {
class Value;
} // namespace base
namespace net {
class HttpRequestHeaders;
}
namespace network {
class SimpleURLLoader;
class SharedURLLoaderFactory;
} // namespace network
namespace journey {
// This class represents a request of journey info. It encapsulates the
// request-response lifecycle. It is also responsible for building and
// serializing the request body protos.
class JourneyInfoJsonRequest {
// Callbacks for JSON parsing to allow injecting platform-dependent code.
using SuccessCallback =
base::RepeatingCallback<void(std::unique_ptr<base::Value> result)>;
using ErrorCallback = base::RepeatingCallback<void(const std::string& error)>;
using ParseJSONCallback =
base::RepeatingCallback<void(const std::string& raw_json_string,
const SuccessCallback& success_callback,
const ErrorCallback& error_callback)>;
using CompletedCallback =
base::OnceCallback<void(std::unique_ptr<base::Value> result,
const std::string& error_detail)>;
public:
// This class is used to build authenticated and non-authenticated
// JourneyInfoJsonRequest.
class Builder {
public:
Builder();
~Builder();
// This method is used to builds a Request object that contains all
// data to fetch new snippets.
std::unique_ptr<JourneyInfoJsonRequest> Build() const;
Builder& SetAuthentication(const std::string& auth_header);
Builder& SetParseJsonCallback(ParseJSONCallback callback);
Builder& SetTimestamps(const std::vector<int64_t>& timestamps);
private:
std::unique_ptr<network::SimpleURLLoader> BuildSimpleURLLoader() const;
net::HttpRequestHeaders BuildSimpleURLLoaderHeaders() const;
// The url for which we're fetching journey info.
GURL url_;
std::string auth_header_;
std::string body_;
ParseJSONCallback parse_json_callback_;
DISALLOW_COPY_AND_ASSIGN(Builder);
};
explicit JourneyInfoJsonRequest(const ParseJSONCallback& callback);
~JourneyInfoJsonRequest();
// This method is used to start fetching journey info using |loader_factory|
// to create a URLLoader, and call |callback| when finished.
void Start(
CompletedCallback callback,
const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory);
// Get the last response as a string
const std::string& GetResponseString() const;
private:
void OnSimpleURLLoaderComplete(std::unique_ptr<std::string> response_body);
void OnJsonParsed(std::unique_ptr<base::Value> result);
void OnJsonError(const std::string& error);
// This callback is called to parse a json string. It contains callbacks for
// error and success cases.
ParseJSONCallback parse_json_callback_;
// The loader for downloading the snippets. Only non-null if a fetch is
// currently ongoing.
std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
std::string last_response_string_;
// The callback to call when journey info are available.
CompletedCallback completed_callback_;
base::WeakPtrFactory<JourneyInfoJsonRequest> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(JourneyInfoJsonRequest);
};
} // namespace journey
#endif // COMPONENTS_JOURNEY_JOURNEY_INFO_JSON_REQUEST_H_
# Copyright 2018 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.
import("//third_party/protobuf/proto_library.gni")
proto_library("proto") {
sources = [
"batch_get_switcher_journey_from_pageload_request.proto",
]
deps = []
}
// Copyright 2018 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.
// Protocol buffer definition for a delta file.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package journey;
message BatchGetSwitcherJourneyFromPageloadRequest {
// Next ID to use: 5
// The timestamps of the pageloads to request journeys from. This will be
// ignored if task_id is present.
// TODO(ghyde): Deprecate this once client moves over.
repeated int64 page_timestamp_usec = 1;
// Override journey creation parameters.
optional JourneyCreationOverrides journey_overrides = 2;
// The maximum number of pageloads allowed per autotabs.
optional int64 max_pageloads = 3 [default = 50];
// The task ids frokm the client to request journeys from.
repeated int64 task_id = 4;
}
message JourneyCreationOverrides {
optional JourneyAlgorithmParameters journey_algorithm_parameters = 1;
}
message JourneyAlgorithmParameters {
// Next ID to use: 11
// Similarity threshold in [0,1]. Clusters with similarity greater
// then this threshold and which were done in short timespans will be
// merged. If set to 1, non temporal merging is performed.
optional float temporal_merge_threshold = 1 [default = 1];
// Similarity threshold in [0,1]. Threshold above which journeys are
// considered to be related to each other.
optional float semantically_related_threshold = 2 [default = 0.1];
// Similarity threshold in [0, 1]. Threshold above which journeys appear in
// searches for a given query.
optional float search_threshold = 3 [default = 0.1];
// If true, dedupe pageloads in journeys by URL. remove_duplicate_titles
// and remove_duplicates_between_tasks will only be used if this value is
// true.
optional bool remove_duplicate_urls = 6 [default = true];
// If true, remove URLs as duplicates if they are from the same domain and
// have the same title. Otherwise, only remove duplicate URLs that have
// identical URLs.
// This value is only used if remove_duplicate_urls is also true.
optional bool remove_duplicate_titles = 4 [default = true];
// If true, remove duplicates across the whole journey. Otherwise,
// only remove duplicates within each task.
// Note: This value is only used if remove_duplicate_urls is also true.
optional bool remove_duplicates_between_tasks = 7 [default = false];
// Type of labels to use for subtitles.
enum SubtitleTermsType {
TYPE_UNKNOWN = 0;
// Use knowledge entities as subtitle terms.
TYPE_KE = 1;
// Use petacat as subtitle terms.
TYPE_PETACAT = 2;
}
optional SubtitleTermsType subtitle_type = 5 [default = TYPE_KE];
// If set to true, bookmarks will be fetched and pageloads will be annotated
// with them.
optional bool get_bookmarks = 8 [default = false];
// The number of days between tasks in the same cluster required in order
// to break into a new journey.
optional int32 journey_break_days = 9 [default = 7];
// The max number of pageloads to be added to a journey.
// NOTE: We will actually add tasks as long as we are under this limit, so
// it is possible that the last task pushes us over.
optional int32 max_pages_in_journey = 10 [default = 500];
}
\ No newline at end of file
...@@ -141,6 +141,7 @@ Refer to README.md for content description and update process. ...@@ -141,6 +141,7 @@ Refer to README.md for content description and update process.
<item id="interest_feed_send" hash_code="76717919" type="0" content_hash_code="34678180" os_list="linux,windows" file_path="components/feed/core/feed_networking_host.cc"/> <item id="interest_feed_send" hash_code="76717919" type="0" content_hash_code="34678180" os_list="linux,windows" file_path="components/feed/core/feed_networking_host.cc"/>
<item id="intranet_redirect_detector" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/> <item id="intranet_redirect_detector" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/>
<item id="invalidation_service" hash_code="72354423" type="0" content_hash_code="78425687" os_list="linux,windows" file_path="components/invalidation/impl/gcm_network_channel.cc"/> <item id="invalidation_service" hash_code="72354423" type="0" content_hash_code="78425687" os_list="linux,windows" file_path="components/invalidation/impl/gcm_network_channel.cc"/>
<item id="journey_journey_info_json_request" hash_code="62660788" type="0" content_hash_code="77009071" os_list="linux,windows" file_path="components/journey/journey_info_json_request.cc"/>
<item id="lib_address_input" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/> <item id="lib_address_input" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/>
<item id="logo_tracker" hash_code="36859107" type="0" content_hash_code="67588075" os_list="linux,windows" file_path="components/search_provider_logos/logo_tracker.cc"/> <item id="logo_tracker" hash_code="36859107" type="0" content_hash_code="67588075" os_list="linux,windows" file_path="components/search_provider_logos/logo_tracker.cc"/>
<item id="md_downloads_dom_handler" hash_code="65603364" type="0" content_hash_code="134779147" os_list="linux,windows" file_path="chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc"/> <item id="md_downloads_dom_handler" hash_code="65603364" type="0" content_hash_code="134779147" os_list="linux,windows" file_path="chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc"/>
...@@ -154,8 +155,8 @@ Refer to README.md for content description and update process. ...@@ -154,8 +155,8 @@ Refer to README.md for content description and update process.
<item id="network_location_provider" hash_code="23472048" type="1" second_id="96590038" content_hash_code="41087976" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="services/device/geolocation/network_location_provider.cc"/> <item id="network_location_provider" hash_code="23472048" type="1" second_id="96590038" content_hash_code="41087976" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="services/device/geolocation/network_location_provider.cc"/>
<item id="network_location_request" hash_code="96590038" type="2" content_hash_code="80741011" os_list="linux,windows" semantics_fields="2,3,4,5" policy_fields="-1" file_path="services/device/geolocation/network_location_request.cc"/> <item id="network_location_request" hash_code="96590038" type="2" content_hash_code="80741011" os_list="linux,windows" semantics_fields="2,3,4,5" policy_fields="-1" file_path="services/device/geolocation/network_location_request.cc"/>
<item id="network_time_component" hash_code="46188932" type="0" content_hash_code="28051857" os_list="linux,windows" file_path="components/network_time/network_time_tracker.cc"/> <item id="network_time_component" hash_code="46188932" type="0" content_hash_code="28051857" os_list="linux,windows" file_path="components/network_time/network_time_tracker.cc"/>
<item id="ntp_custom_link_checker_request" hash_code="78408551" type="0" deprecated="2018-10-26" content_hash_code="13407730" file_path=""/>
<item id="ntp_contextual_suggestions_fetch" hash_code="95711309" type="0" content_hash_code="107035434" os_list="linux,windows" file_path="components/ntp_snippets/contextual/contextual_suggestions_fetch.cc"/> <item id="ntp_contextual_suggestions_fetch" hash_code="95711309" type="0" content_hash_code="107035434" os_list="linux,windows" file_path="components/ntp_snippets/contextual/contextual_suggestions_fetch.cc"/>
<item id="ntp_custom_link_checker_request" hash_code="78408551" type="0" deprecated="2018-10-26" content_hash_code="13407730" file_path=""/>
<item id="ntp_icon_source" hash_code="29197139" type="0" content_hash_code="16399294" os_list="linux,windows" file_path="chrome/browser/search/ntp_icon_source.cc"/> <item id="ntp_icon_source" hash_code="29197139" type="0" content_hash_code="16399294" os_list="linux,windows" file_path="chrome/browser/search/ntp_icon_source.cc"/>
<item id="ntp_snippets_fetch" hash_code="15418154" type="0" content_hash_code="10078959" os_list="linux,windows" file_path="components/ntp_snippets/remote/json_request.cc"/> <item id="ntp_snippets_fetch" hash_code="15418154" type="0" content_hash_code="10078959" os_list="linux,windows" file_path="components/ntp_snippets/remote/json_request.cc"/>
<item id="oauth2_access_token_fetcher" hash_code="27915688" type="0" content_hash_code="33501872" os_list="linux,windows" file_path="google_apis/gaia/oauth2_access_token_fetcher_impl.cc"/> <item id="oauth2_access_token_fetcher" hash_code="27915688" type="0" content_hash_code="33501872" os_list="linux,windows" file_path="google_apis/gaia/oauth2_access_token_fetcher_impl.cc"/>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment