Commit fa18d177 authored by Alice Gong's avatar Alice Gong Committed by Chromium LUCI CQ

Implement first 2 OAuth2 flows for Box: FindFolder and CreateFolder

BUG=1157672

Change-Id: Ib31d8dd60486f8634d9477ad82d5d9bbbc095dea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2590428
Commit-Queue: Alice Gong <alicego@google.com>
Reviewed-by: default avatarMarc-André Decoste <mad@chromium.org>
Reviewed-by: default avatarMartin Šrámek <msramek@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarDominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#840319}
parent 704d9509
......@@ -3571,6 +3571,10 @@ static_library("browser") {
"enterprise/connectors/content_analysis_dialog.h",
"enterprise/connectors/enterprise_connectors_policy_handler.cc",
"enterprise/connectors/enterprise_connectors_policy_handler.h",
"enterprise/connectors/file_system/box_api_call_endpoints.cc",
"enterprise/connectors/file_system/box_api_call_endpoints.h",
"enterprise/connectors/file_system/box_api_call_flow.cc",
"enterprise/connectors/file_system/box_api_call_flow.h",
"enterprise/connectors/reporting_service_settings.cc",
"enterprise/connectors/reporting_service_settings.h",
"enterprise/connectors/service_provider_config.cc",
......
rogerta@chromium.org
alicego@google.com
// Copyright 2020 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/enterprise/connectors/file_system/box_api_call_endpoints.h"
namespace enterprise_connectors {
const char kFileSystemBoxEndpointApi[] = "https://api.box.com/";
} // namespace enterprise_connectors
// Copyright 2020 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 CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_API_CALL_ENDPOINTS_H_
#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_API_CALL_ENDPOINTS_H_
namespace enterprise_connectors {
extern const char kFileSystemBoxEndpointApi[];
} // namespace enterprise_connectors
#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_API_CALL_ENDPOINTS_H_
// Copyright 2020 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/enterprise/connectors/file_system/box_api_call_flow.h"
#include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/enterprise/connectors/file_system/box_api_call_endpoints.h"
#include "net/base/escape.h"
#include "net/http/http_status_code.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
namespace {
static const char kParentFolderId[] = "0"; // Create folder at root.
std::string ExtractFolderId(const base::Value& entry) {
const base::Value* folder_id = entry.FindPath("id");
if (!folder_id) {
DLOG(ERROR) << "[BoxApiCallFlow] Can't find folder id!";
return std::string();
}
std::string id;
if (folder_id->type() == base::Value::Type::STRING) {
id = folder_id->GetString();
} else if (folder_id->type() == base::Value::Type::INTEGER) {
id = base::NumberToString(folder_id->GetInt());
} else {
const char* type_name = folder_id->GetTypeName(folder_id->type());
DLOG(ERROR) << "[BoxApiCallFlow] Invalid folder_id type: " << type_name;
}
return id;
}
} // namespace
namespace enterprise_connectors {
BoxApiCallFlow::BoxApiCallFlow() = default;
BoxApiCallFlow::~BoxApiCallFlow() = default;
GURL BoxApiCallFlow::CreateApiCallUrl() {
return GURL(kFileSystemBoxEndpointApi);
}
std::string BoxApiCallFlow::CreateApiCallBody() {
return std::string();
}
std::string BoxApiCallFlow::CreateApiCallBodyContentType() {
return "application/json";
}
// Box API reference:
net::PartialNetworkTrafficAnnotationTag
BoxApiCallFlow::GetNetworkTrafficAnnotationTag() {
return net::DefinePartialNetworkTrafficAnnotation(
"file_system_connector_to_box", "oauth2_api_call_flow", R"(
semantics {
sender: "Chrome Enterprise File System Connector"
description:
"Communication to Box API (https://developer.box.com/reference/) to "
"upload or download files."
trigger:
"A request from the user to download a file when the enterprise admin"
" has enabled file download redirection."
data: "Any file that is being downloaded/uploaded by the user."
destination: OTHER
destination_other: "Box storage in the cloud."
}
policy {
cookies_allowed: NO
setting:
"No settings control."
chrome_policy {}
})");
// TODO(1157959): Add the policy that will turn on/off the connector here?
}
////////////////////////////////////////////////////////////////////////////////
// FindUpstreamFolder
////////////////////////////////////////////////////////////////////////////////
// BoxApiCallFlow interface.
// API reference:
// https://developer.box.com/reference/get-search/#param-200-application/json
BoxFindUpstreamFolderApiCallFlow::BoxFindUpstreamFolderApiCallFlow(
TaskCallback callback)
: callback_(std::move(callback)) {}
BoxFindUpstreamFolderApiCallFlow::~BoxFindUpstreamFolderApiCallFlow() = default;
GURL BoxFindUpstreamFolderApiCallFlow::CreateApiCallUrl() {
std::string path("2.0/search?type=folder&query=ChromeDownloads");
GURL call_url = BoxApiCallFlow::CreateApiCallUrl().Resolve(path);
return call_url;
}
void BoxFindUpstreamFolderApiCallFlow::ProcessApiCallSuccess(
const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) {
auto response_code = head->headers->response_code();
CHECK_EQ(response_code, net::HTTP_OK);
data_decoder::DataDecoder::ParseJsonIsolated(
*body, base::BindOnce(&BoxFindUpstreamFolderApiCallFlow::OnJsonParsed,
weak_factory_.GetWeakPtr()));
}
void BoxFindUpstreamFolderApiCallFlow::ProcessApiCallFailure(
int net_error,
const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) {
auto response_code = head->headers->response_code();
DLOG(ERROR)
<< "[BoxApiCallFlow] FindUpstreamFolder API call failed; net_error = "
<< net_error << "; response_code = " << response_code;
std::move(callback_).Run(false, response_code, std::string());
}
void BoxFindUpstreamFolderApiCallFlow::OnJsonParsed(
data_decoder::DataDecoder::ValueOrError result) {
if (!result.value) {
DLOG(ERROR) << "[BoxApiCallFlow] FindUpstreamFolder OnJsonParsed Error: "
<< result.error->data();
std::move(callback_).Run(false, net::HTTP_OK, std::string());
return;
}
const base::Value* entries = result.value->FindPath("entries");
if (entries && entries->is_list()) {
auto entries_list = entries->GetList();
if (!entries_list.empty()) {
std::string folder_id = ExtractFolderId(entries_list.front());
std::move(callback_).Run(!folder_id.empty(), net::HTTP_OK, folder_id);
} else {
// Can't find folder, so return empty id but success status.
std::move(callback_).Run(true, net::HTTP_OK, std::string());
}
return;
}
DLOG(ERROR) << "[BoxApiCallFlow] FindUpstreamFolder returned invalid entries";
std::move(callback_).Run(false, net::HTTP_OK, std::string());
return;
}
////////////////////////////////////////////////////////////////////////////////
// CreateUpstreamFolder
////////////////////////////////////////////////////////////////////////////////
// BoxApiCallFlow interface.
// API reference: https://developer.box.com/reference/post-folders/
BoxCreateUpstreamFolderApiCallFlow::BoxCreateUpstreamFolderApiCallFlow(
TaskCallback callback)
: callback_(std::move(callback)) {}
BoxCreateUpstreamFolderApiCallFlow::~BoxCreateUpstreamFolderApiCallFlow() =
default;
GURL BoxCreateUpstreamFolderApiCallFlow::CreateApiCallUrl() {
return BoxApiCallFlow::CreateApiCallUrl().Resolve("2.0/folders");
}
std::string BoxCreateUpstreamFolderApiCallFlow::CreateApiCallBody() {
base::Value val(base::Value::Type::DICTIONARY);
val.SetStringKey("name", "ChromeDownloads");
base::Value parent_val(base::Value::Type::DICTIONARY);
parent_val.SetStringKey("id", kParentFolderId);
val.SetKey("parent", std::move(parent_val));
std::string body;
base::JSONWriter::Write(val, &body);
return body;
}
bool BoxCreateUpstreamFolderApiCallFlow::IsExpectedSuccessCode(int code) const {
return code == net::HTTP_CREATED;
}
void BoxCreateUpstreamFolderApiCallFlow::ProcessApiCallSuccess(
const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) {
auto response_code = head->headers->response_code();
CHECK_EQ(response_code, net::HTTP_CREATED);
data_decoder::DataDecoder::ParseJsonIsolated(
*body, base::BindOnce(&BoxCreateUpstreamFolderApiCallFlow::OnJsonParsed,
weak_factory_.GetWeakPtr()));
}
void BoxCreateUpstreamFolderApiCallFlow::ProcessApiCallFailure(
int net_error,
const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) {
auto response_code = head->headers->response_code();
DLOG(ERROR)
<< "[BoxApiCallFlow] CreateUpstreamFolder API call failed; net error = "
<< net_error << "; response code = " << response_code;
std::move(callback_).Run(false, response_code, std::string());
}
void BoxCreateUpstreamFolderApiCallFlow::OnJsonParsed(
data_decoder::DataDecoder::ValueOrError result) {
std::string folder_id;
if (result.value) {
folder_id = ExtractFolderId(*result.value);
} else {
DLOG(ERROR) << "[BoxApiCallFlow] CreateUpstreamFolder OnJsonParsed Error: "
<< result.error->data();
}
// TODO(1157641): store folder_id in profile pref to handle indexing latency.
std::move(callback_).Run(!folder_id.empty(), net::HTTP_OK, folder_id);
return;
}
} // namespace enterprise_connectors
// Copyright 2020 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 CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_API_CALL_FLOW_H_
#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_API_CALL_FLOW_H_
#include "base/callback.h"
#include "google_apis/gaia/oauth2_api_call_flow.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
namespace enterprise_connectors {
// Helper for making Box API calls.
//
// This class is abstract. The methods OAuth2ApiCallFlow::ProcessApiCallXXX must
// be implemented by subclasses.
class BoxApiCallFlow : public OAuth2ApiCallFlow {
public:
BoxApiCallFlow();
~BoxApiCallFlow() override;
// OAuth2ApiCallFlow interface.
GURL CreateApiCallUrl() override;
std::string CreateApiCallBody() override;
std::string CreateApiCallBodyContentType() override;
net::PartialNetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag()
override;
};
// Helper for finding the downloads folder in box.
class BoxFindUpstreamFolderApiCallFlow : public BoxApiCallFlow {
public:
using TaskCallback = base::OnceCallback<void(bool, int, const std::string&)>;
explicit BoxFindUpstreamFolderApiCallFlow(TaskCallback callback);
~BoxFindUpstreamFolderApiCallFlow() override;
protected:
// BoxApiCallFlow interface.
GURL CreateApiCallUrl() override;
void ProcessApiCallSuccess(const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) override;
void ProcessApiCallFailure(int net_error,
const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) override;
private:
// Callback for JsonParser that extracts folder id in ProcessApiCallSuccess().
void OnJsonParsed(data_decoder::DataDecoder::ValueOrError result);
// Callback from the controller to report success, http_code, folder_id.
TaskCallback callback_;
base::WeakPtrFactory<BoxFindUpstreamFolderApiCallFlow> weak_factory_{this};
};
// Helper for creating an upstream downloads folder in box.
class BoxCreateUpstreamFolderApiCallFlow : public BoxApiCallFlow {
public:
using TaskCallback = base::OnceCallback<void(bool, int, const std::string&)>;
explicit BoxCreateUpstreamFolderApiCallFlow(TaskCallback callback);
~BoxCreateUpstreamFolderApiCallFlow() override;
protected:
// BoxApiCallFlow interface.
GURL CreateApiCallUrl() override;
std::string CreateApiCallBody() override;
bool IsExpectedSuccessCode(int code) const override;
void ProcessApiCallSuccess(const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) override;
void ProcessApiCallFailure(int net_error,
const network::mojom::URLResponseHead* head,
std::unique_ptr<std::string> body) override;
private:
// Callback for JsonParser that extracts folder id in ProcessApiCallSuccess().
void OnJsonParsed(data_decoder::DataDecoder::ValueOrError result);
// Callback from the controller to report success, http_code, folder_id.
TaskCallback callback_;
base::WeakPtrFactory<BoxCreateUpstreamFolderApiCallFlow> weak_factory_{this};
};
} // namespace enterprise_connectors
#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_BOX_API_CALL_FLOW_H_
// Copyright 2020 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.
//
// A complete set of unit tests for all subclasses of BoxApiCallFlow.
#include "chrome/browser/enterprise/connectors/file_system/box_api_call_flow.h"
#include <memory>
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "services/network/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace enterprise_connectors {
template <typename ApiCallMiniClass>
class BoxApiCallFlowTest : public testing::Test {
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
std::unique_ptr<ApiCallMiniClass> flow_;
bool processed_success_ = false;
std::string processed_folder_id_ = "default id";
};
////////////////////////////////////////////////////////////////////////////////
// FindUpstreamFolder
////////////////////////////////////////////////////////////////////////////////
class BoxFindUpstreamFolderApiCallFlowForTest
: public BoxFindUpstreamFolderApiCallFlow {
public:
using BoxFindUpstreamFolderApiCallFlow::BoxFindUpstreamFolderApiCallFlow;
using BoxFindUpstreamFolderApiCallFlow::CreateApiCallUrl;
using BoxFindUpstreamFolderApiCallFlow::ProcessApiCallFailure;
using BoxFindUpstreamFolderApiCallFlow::ProcessApiCallSuccess;
private:
DISALLOW_COPY_AND_ASSIGN(BoxFindUpstreamFolderApiCallFlowForTest);
};
class BoxFindUpstreamFolderApiCallFlowTest
: public BoxApiCallFlowTest<BoxFindUpstreamFolderApiCallFlowForTest> {
protected:
void SetUp() override {
flow_ = std::make_unique<BoxFindUpstreamFolderApiCallFlowForTest>(
base::BindOnce(&BoxFindUpstreamFolderApiCallFlowTest::OnResponse,
factory_.GetWeakPtr()));
}
void OnResponse(bool success,
int response_code,
const std::string& folder_id) {
processed_success_ = success;
processed_folder_id_ = folder_id;
}
base::WeakPtrFactory<BoxFindUpstreamFolderApiCallFlowTest> factory_{this};
};
TEST_F(BoxFindUpstreamFolderApiCallFlowTest, CreateApiCallUrl) {
GURL url("https://api.box.com/2.0/search?type=folder&query=ChromeDownloads");
ASSERT_EQ(flow_->CreateApiCallUrl(), url);
}
TEST_F(BoxFindUpstreamFolderApiCallFlowTest, ProcessApiCallFailure) {
auto http_head = network::CreateURLResponseHead(net::HTTP_BAD_REQUEST);
flow_->ProcessApiCallFailure(net::OK, http_head.get(), {});
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(processed_success_);
ASSERT_EQ(processed_folder_id_, "");
}
class BoxFindUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess
: public BoxFindUpstreamFolderApiCallFlowTest {
protected:
void SetUp() override {
BoxFindUpstreamFolderApiCallFlowTest::SetUp();
head_ = network::CreateURLResponseHead(net::HTTP_OK);
}
data_decoder::test::InProcessDataDecoder decoder_;
network::mojom::URLResponseHeadPtr head_;
};
TEST_F(BoxFindUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess, EmptyBody) {
flow_->ProcessApiCallSuccess(head_.get(), std::make_unique<std::string>());
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(processed_success_);
ASSERT_EQ(processed_folder_id_, "");
}
TEST_F(BoxFindUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess,
InvalidBody) {
flow_->ProcessApiCallSuccess(head_.get(),
std::make_unique<std::string>("adgafdga"));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(processed_success_);
ASSERT_EQ(processed_folder_id_, "");
}
TEST_F(BoxFindUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess,
EmptyEntries) {
std::string body(R"({
"entries": [
]
})");
flow_->ProcessApiCallSuccess(head_.get(),
std::make_unique<std::string>(body));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(processed_success_) << body;
ASSERT_EQ(processed_folder_id_, "");
}
TEST_F(BoxFindUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess,
ValidEntries) {
std::string body(R"({
"entries": [
{
"id": 12345,
"etag": 1,
"type": "folder",
"sequence_id": 3,
"name": "ChromeDownloads"
}
]
})");
flow_->ProcessApiCallSuccess(head_.get(),
std::make_unique<std::string>(body));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(processed_success_);
ASSERT_EQ(processed_folder_id_, "12345");
}
////////////////////////////////////////////////////////////////////////////////
// CreateUpstreamFolder
////////////////////////////////////////////////////////////////////////////////
class BoxCreateUpstreamFolderApiCallFlowForTest
: public BoxCreateUpstreamFolderApiCallFlow {
public:
using BoxCreateUpstreamFolderApiCallFlow::BoxCreateUpstreamFolderApiCallFlow;
using BoxCreateUpstreamFolderApiCallFlow::CreateApiCallBody;
using BoxCreateUpstreamFolderApiCallFlow::CreateApiCallUrl;
using BoxCreateUpstreamFolderApiCallFlow::IsExpectedSuccessCode;
using BoxCreateUpstreamFolderApiCallFlow::ProcessApiCallFailure;
using BoxCreateUpstreamFolderApiCallFlow::ProcessApiCallSuccess;
private:
DISALLOW_COPY_AND_ASSIGN(BoxCreateUpstreamFolderApiCallFlowForTest);
};
class BoxCreateUpstreamFolderApiCallFlowTest
: public BoxApiCallFlowTest<BoxCreateUpstreamFolderApiCallFlowForTest> {
protected:
void SetUp() override {
flow_ = std::make_unique<BoxCreateUpstreamFolderApiCallFlowForTest>(
base::BindOnce(&BoxCreateUpstreamFolderApiCallFlowTest::OnResponse,
factory_.GetWeakPtr()));
}
void OnResponse(bool success,
int response_code,
const std::string& folder_id) {
processed_success_ = success;
processed_folder_id_ = folder_id;
}
base::WeakPtrFactory<BoxCreateUpstreamFolderApiCallFlowTest> factory_{this};
};
TEST_F(BoxCreateUpstreamFolderApiCallFlowTest, CreateApiCallUrl) {
GURL url("https://api.box.com/2.0/folders");
ASSERT_EQ(flow_->CreateApiCallUrl(), url);
}
TEST_F(BoxCreateUpstreamFolderApiCallFlowTest, CreateApiCallBody) {
std::string body = flow_->CreateApiCallBody();
std::string expected_body(
R"({"name":"ChromeDownloads","parent":{"id":"0"}})");
ASSERT_EQ(body, expected_body);
}
TEST_F(BoxCreateUpstreamFolderApiCallFlowTest, IsExpectedSuccessCode) {
ASSERT_TRUE(flow_->IsExpectedSuccessCode(201));
ASSERT_FALSE(flow_->IsExpectedSuccessCode(400));
ASSERT_FALSE(flow_->IsExpectedSuccessCode(403));
ASSERT_FALSE(flow_->IsExpectedSuccessCode(404));
ASSERT_FALSE(flow_->IsExpectedSuccessCode(409));
}
TEST_F(BoxCreateUpstreamFolderApiCallFlowTest, ProcessApiCallFailure) {
auto http_head = network::CreateURLResponseHead(net::HTTP_BAD_REQUEST);
flow_->ProcessApiCallFailure(net::OK, http_head.get(), {});
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(processed_success_);
ASSERT_EQ(processed_folder_id_, "");
}
class BoxCreateUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess
: public BoxCreateUpstreamFolderApiCallFlowTest {
public:
BoxCreateUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess()
: head_(network::CreateURLResponseHead(net::HTTP_CREATED)) {}
protected:
data_decoder::test::InProcessDataDecoder decoder_;
network::mojom::URLResponseHeadPtr head_;
};
TEST_F(BoxCreateUpstreamFolderApiCallFlowTest_ProcessApiCallSuccess, Normal) {
std::string body(R"({
"id": 12345,
"type": "folder",
"content_created_at": "2012-12-12T10:53:43-08:00",
"content_modified_at": "2012-12-12T10:53:43-08:00",
"created_at": "2012-12-12T10:53:43-08:00",
"created_by": {
"id": 11446498,
"type": "user",
"login": "ceo@example.com",
"name": "Aaron Levie"
},
"description": "Legal contracts for the new ACME deal",
"etag": 1,
"expires_at": "2012-12-12T10:53:43-08:00",
"folder_upload_email": {
"access": "open",
"email": "upload.Contracts.asd7asd@u.box.com"
},
"name": "ChromeDownloads",
"owned_by": {
"id": 11446498,
"type": "user",
"login": "ceo@example.com",
"name": "Aaron Levie"
},
"parent": {
"id": 0,
"type": "folder",
"etag": 1,
"name": "",
"sequence_id": 3
}
})");
auto http_head = network::CreateURLResponseHead(net::HTTP_CREATED);
flow_->ProcessApiCallSuccess(http_head.get(),
std::make_unique<std::string>(body));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(processed_success_);
ASSERT_EQ(processed_folder_id_, "12345");
}
} // namespace enterprise_connectors
......@@ -5766,6 +5766,10 @@ test("unit_tests") {
sources += [ "../browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc" ]
}
if (is_linux || is_chromeos || is_mac || is_win) {
sources += [ "../browser/enterprise/connectors/file_system/box_api_call_flow_unittests.cc" ]
}
if (enable_plugins) {
sources += [
"../browser/metrics/plugin_metrics_provider_unittest.cc",
......
......@@ -112,6 +112,7 @@ Refer to README.md for content description and update process.
<item id="family_info" added_in_milestone="62" hash_code="30913825" type="0" deprecated="2019-07-30" content_hash_code="25369370" file_path=""/>
<item id="favicon_loader" added_in_milestone="63" hash_code="112189210" type="0" content_hash_code="70773116" os_list="linux,windows" file_path="content/renderer/loader/web_url_loader_impl.cc"/>
<item id="feed_image_fetcher" added_in_milestone="68" hash_code="87439531" type="0" deprecated="2019-01-04" content_hash_code="26756208" file_path=""/>
<item id="file_system_connector_to_box" added_in_milestone="89" hash_code="29061438" type="1" second_id="29188932" content_hash_code="69177828" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="-1,3,4" file_path="chrome/browser/enterprise/connectors/file_system/box_api_call_flow.cc"/>
<item id="floc_id_provider_impl" added_in_milestone="85" hash_code="103052331" type="1" second_id="13704791" content_hash_code="41421380" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="3" file_path="chrome/browser/federated_learning/floc_id_provider_impl.cc"/>
<item id="floc_remote_permission_service" added_in_milestone="85" hash_code="13704791" type="2" content_hash_code="86293622" os_list="linux,windows" semantics_fields="1,5" policy_fields="1,2,4" file_path="chrome/browser/federated_learning/floc_remote_permission_service.cc"/>
<item id="ftl_messaging_client_ack_messages" added_in_milestone="86" hash_code="55663676" type="0" content_hash_code="20913627" os_list="linux,windows" file_path="remoting/signaling/ftl_messaging_client.cc"/>
......
......@@ -74,6 +74,7 @@ hidden="true" so that these annotations don't show up in the document.
<traffic_annotation unique_id="cast_socket"/>
<traffic_annotation unique_id="dom_distiller"/>
<traffic_annotation unique_id="download_manager_resume"/>
<traffic_annotation unique_id="file_system_connector_to_box"/>
<traffic_annotation unique_id="parallel_download_job"/>
<traffic_annotation unique_id="interest_feedv2_send"/>
<traffic_annotation unique_id="mirroring_get_setup_info"/>
......
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