blob: 18fe199dd9dccafa22b2bb1eb382118c9551b5b0 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/attribution_reporting/attribution_debug_report.h"
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "content/browser/attribution_reporting/common_source_info.h"
#include "content/browser/attribution_reporting/storable_source.h"
#include "net/base/schemeful_site.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace content {
namespace {
absl::optional<AttributionDebugReport::DataType> GetReportDataType(
StorableSource::Result result,
bool is_debug_cookie_set) {
switch (result) {
case StorableSource::Result::kSuccess:
case StorableSource::Result::kInternalError:
case StorableSource::Result::kInsufficientSourceCapacity:
case StorableSource::Result::kExcessiveReportingOrigins:
case StorableSource::Result::kProhibitedByBrowserPolicy:
return absl::nullopt;
case StorableSource::Result::kInsufficientUniqueDestinationCapacity:
return AttributionDebugReport::DataType::kSourceDestinationLimit;
case StorableSource::Result::kSuccessNoised:
return is_debug_cookie_set
? absl::make_optional(
AttributionDebugReport::DataType::kSourceNoised)
: absl::nullopt;
}
}
std::string SerializeReportDataType(
AttributionDebugReport::DataType data_type) {
switch (data_type) {
case AttributionDebugReport::DataType::kSourceDestinationLimit:
return "source-destination-limit";
case AttributionDebugReport::DataType::kSourceNoised:
return "source-noised";
}
}
base::Value::Dict GetReportDataBody(
AttributionDebugReport::DataType data_type,
const StorableSource& source,
absl::optional<int> max_destinations_per_source_site_reporting_origin) {
const CommonSourceInfo& common_info = source.common_info();
base::Value::Dict data_body;
data_body.Set("attribution_destination",
common_info.DestinationSite().Serialize());
data_body.Set("source_event_id",
base::NumberToString(common_info.source_event_id()));
if (!source.is_within_fenced_frame())
data_body.Set("source_site", common_info.SourceSite().Serialize());
switch (data_type) {
case AttributionDebugReport::DataType::kSourceDestinationLimit:
DCHECK(max_destinations_per_source_site_reporting_origin);
data_body.Set("limit",
*max_destinations_per_source_site_reporting_origin);
break;
case AttributionDebugReport::DataType::kSourceNoised:
break;
}
return data_body;
}
} // namespace
class AttributionDebugReport::ReportData {
public:
ReportData(DataType type, base::Value::Dict body);
~ReportData();
ReportData(const ReportData&) = delete;
ReportData& operator=(const ReportData&) = delete;
ReportData(ReportData&&);
ReportData& operator=(ReportData&&);
base::Value::Dict SerializeAsJson() const;
private:
DataType type_;
base::Value::Dict body_;
};
AttributionDebugReport::ReportData::ReportData(DataType type,
base::Value::Dict body)
: type_(type), body_(std::move(body)) {}
AttributionDebugReport::ReportData::~ReportData() = default;
AttributionDebugReport::ReportData::ReportData(ReportData&&) = default;
AttributionDebugReport::ReportData&
AttributionDebugReport::ReportData::operator=(ReportData&&) = default;
base::Value::Dict AttributionDebugReport::ReportData::SerializeAsJson() const {
base::Value::Dict dict;
dict.Set("type", SerializeReportDataType(type_));
dict.Set("body", body_.Clone());
return dict;
}
// static
absl::optional<AttributionDebugReport> AttributionDebugReport::Create(
const StorableSource& source,
bool is_debug_cookie_set,
const AttributionStorage::StoreSourceResult& result) {
if (!source.debug_reporting())
return absl::nullopt;
absl::optional<DataType> data_type =
GetReportDataType(result.status, is_debug_cookie_set);
if (!data_type)
return absl::nullopt;
std::vector<ReportData> report_data;
report_data.emplace_back(
*data_type,
GetReportDataBody(
*data_type, source,
result.max_destinations_per_source_site_reporting_origin));
return AttributionDebugReport(std::move(report_data),
source.common_info().reporting_origin());
}
AttributionDebugReport::AttributionDebugReport(
std::vector<ReportData> report_data,
url::Origin reporting_origin)
: report_data_(std::move(report_data)),
reporting_origin_(std::move(reporting_origin)) {
DCHECK(!report_data_.empty());
DCHECK(network::IsOriginPotentiallyTrustworthy(reporting_origin_));
}
AttributionDebugReport::~AttributionDebugReport() = default;
AttributionDebugReport::AttributionDebugReport(AttributionDebugReport&&) =
default;
AttributionDebugReport& AttributionDebugReport::operator=(
AttributionDebugReport&&) = default;
base::Value::List AttributionDebugReport::ReportBody() const {
base::Value::List report_body;
for (const ReportData& data : report_data_) {
report_body.Append(data.SerializeAsJson());
}
return report_body;
}
GURL AttributionDebugReport::ReportURL() const {
static constexpr char kPath[] =
"/.well-known/attribution-reporting/debug/verbose";
GURL::Replacements replacements;
replacements.SetPathStr(kPath);
return reporting_origin_.GetURL().ReplaceComponents(replacements);
}
} // namespace content