#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_STORAGE_SQL_H_
#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_STORAGE_SQL_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <variant>
#include <vector>
#include "base/containers/enum_set.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/types/expected.h"
#include "content/browser/attribution_reporting/aggregatable_debug_rate_limit_table.h"
#include "content/browser/attribution_reporting/attribution_report.h"
#include "content/browser/attribution_reporting/create_report_result.h"
#include "content/browser/attribution_reporting/os_registrations_table.h"
#include "content/browser/attribution_reporting/rate_limit_table.h"
#include "content/browser/attribution_reporting/stored_source.h"
#include "content/common/content_export.h"
#include "content/public/browser/attribution_data_model.h"
#include "content/public/browser/storage_partition.h"
#include "sql/database.h"
#include "sql/transaction.h"
#include "third_party/blink/public/mojom/aggregation_service/aggregatable_report.mojom-forward.h"
namespace attribution_reporting {
class AggregatableNamedBudgetCandidate;
class AggregatableTriggerConfig;
class SuitableOrigin;
}
namespace base {
class Time;
class TimeDelta;
class Uuid;
}
namespace net {
class SchemefulSite;
}
namespace sql {
class Statement;
}
namespace url {
class Origin;
}
namespace content {
class AggregatableDebugReport;
class AttributionResolverDelegate;
class AttributionTrigger;
class CreateReportResult;
class StorableSource;
struct AttributionInfo;
enum class RateLimitResult : int;
class CONTENT_EXPORT AttributionStorageSql {
public:
static constexpr int kCurrentVersionNumber = 70;
static constexpr int kCompatibleVersionNumber = 70;
static constexpr int kDeprecatedVersionNumber = 55;
static_assert(kCompatibleVersionNumber <= kCurrentVersionNumber);
static_assert(kDeprecatedVersionNumber < kCompatibleVersionNumber);
class Transaction {
public:
Transaction(const Transaction&) = delete;
Transaction& operator=(const Transaction&) = delete;
Transaction(Transaction&&) = delete;
Transaction& operator=(Transaction&&) = delete;
~Transaction();
[[nodiscard]] bool Commit();
private:
friend class AttributionStorageSql;
static std::unique_ptr<Transaction> CreateAndStart(sql::Database& db);
explicit Transaction(sql::Database& db);
sql::Transaction transaction_;
};
struct Error {};
AttributionStorageSql(const base::FilePath& user_data_directory,
AttributionResolverDelegate* delegate);
AttributionStorageSql(const AttributionStorageSql&) = delete;
AttributionStorageSql& operator=(const AttributionStorageSql&) = delete;
AttributionStorageSql(AttributionStorageSql&&) = delete;
AttributionStorageSql& operator=(AttributionStorageSql&&) = delete;
~AttributionStorageSql();
enum class InitStatus {
kSuccess = 0,
kFailedToOpenDbInMemory = 1,
kFailedToOpenDbFile = 2,
kFailedToCreateDir = 3,
kFailedToInitializeSchema = 4,
kMaxValue = kFailedToInitializeSchema,
};
enum class ReportCorruptionStatus {
kAnyFieldCorrupted = 0,
kInvalidFailedSendAttempts = 1,
kInvalidExternalReportID = 2,
kInvalidContextOrigin = 3,
kInvalidReportingOrigin = 4,
kInvalidReportType = 5,
kReportingOriginMismatch = 6,
kSourceDataMissingEventLevel = 8,
kSourceDataMissingAggregatable = 9,
kSourceDataFoundNullAggregatable = 10,
kInvalidMetadata = 11,
kSourceNotFound = 12,
kSourceInvalidSourceOrigin = 13,
kSourceInvalidReportingOrigin = 14,
kSourceInvalidSourceType = 15,
kSourceInvalidAttributionLogic = 16,
kSourceInvalidNumConversions = 17,
kSourceInvalidNumAggregatableReports = 18,
kSourceInvalidAggregationKeys = 19,
kSourceInvalidFilterData = 20,
kSourceInvalidActiveState = 21,
kSourceInvalidReadOnlySourceData = 22,
kSourceInvalidEventReportWindows = 23,
kSourceInvalidMaxEventLevelReports = 24,
kSourceInvalidEventLevelEpsilon = 25,
kSourceDestinationSitesQueryFailed = 26,
kSourceInvalidDestinationSites = 27,
kStoredSourceConstructionFailed = 28,
kSourceInvalidTriggerData = 29,
kSourceDedupKeyQueryFailed = 30,
kSourceInvalidRandomizedResponseRate = 31,
kSourceInvalidAttributionScopesData = 32,
kSourceInvalidAggregatableNamedBudgets = 33,
kMaxValue = kSourceInvalidAggregatableNamedBudgets,
};
struct DeletionCounts {
int sources = 0;
int reports = 0;
};
struct AggregatableDebugSourceData {
int remaining_budget;
int num_reports;
};
[[nodiscard]] std::unique_ptr<Transaction> StartTransaction();
void VerifyReports(DeletionCounts* deletion_counts);
[[nodiscard]] std::optional<StoredSource> InsertSource(
const StorableSource& source,
base::Time source_time,
int num_attributions,
bool event_level_active,
double randomized_response_rate,
StoredSource::AttributionLogic attribution_logic,
base::Time aggregatable_report_window_time);
[[nodiscard]] bool UpdateOrRemoveSourcesWithIncompatibleScopeFields(
const StorableSource&,
base::Time source_time);
[[nodiscard]] bool RemoveSourcesWithOutdatedScopes(const StorableSource&,
base::Time source_time);
CreateReportResult MaybeCreateAndStoreReport(AttributionTrigger);
std::vector<AttributionReport> GetAttributionReports(
base::Time max_report_time,
int limit = -1);
std::optional<base::Time> GetNextReportTime(base::Time time);
std::optional<AttributionReport> GetReport(AttributionReport::Id);
std::vector<StoredSource> GetActiveSources(int limit = -1);
std::set<AttributionDataModel::DataKey> GetAllDataKeys();
bool DeleteReport(AttributionReport::Id report_id);
bool UpdateReportForSendFailure(AttributionReport::Id report_id,
base::Time new_report_time);
bool AdjustOfflineReportTimes(base::TimeDelta min_delay,
base::TimeDelta max_delay);
void ClearAllDataAllTime(bool delete_rate_limit_data);
void ClearDataWithFilter(
base::Time delete_begin,
base::Time delete_end,
std::variant<StoragePartition::StorageKeyMatcherFunction, url::Origin>
filter_or_origin,
bool delete_rate_limit_data);
[[nodiscard]] std::optional<AggregatableDebugSourceData>
GetAggregatableDebugSourceData(StoredSource::Id);
[[nodiscard]] AggregatableDebugRateLimitTable::Result
AggregatableDebugReportAllowedForRateLimit(const AggregatableDebugReport&);
[[nodiscard]] bool AdjustForAggregatableDebugReport(
const AggregatableDebugReport&,
std::optional<StoredSource::Id>);
void StoreOsRegistrations(const base::flat_set<url::Origin>&);
void SetDelegate(AttributionResolverDelegate*);
[[nodiscard]] bool AddRateLimitForSource(const StoredSource& source,
int64_t destination_limit_priority);
[[nodiscard]] bool AddRateLimitForAttribution(
const AttributionInfo& attribution_info,
const StoredSource& source,
RateLimitTable::Scope scope,
AttributionReport::Id id);
[[nodiscard]] RateLimitResult SourceAllowedForReportingOriginLimit(
const StorableSource& source,
base::Time source_time);
[[nodiscard]] RateLimitResult SourceAllowedForReportingOriginPerSiteLimit(
const StorableSource& source,
base::Time source_time);
[[nodiscard]] RateLimitResult SourceAllowedForDestinationPerDayRateLimit(
const StorableSource& source,
base::Time source_time);
[[nodiscard]] RateLimitTable::DestinationRateLimitResult
SourceAllowedForDestinationRateLimit(const StorableSource& source,
base::Time source_time);
[[nodiscard]] RateLimitResult AttributionAllowedForReportingOriginLimit(
const AttributionInfo& attribution_info,
const StoredSource& source);
[[nodiscard]] RateLimitResult AttributionAllowedForAttributionLimit(
const AttributionInfo& attribution_info,
const StoredSource& source,
RateLimitTable::Scope scope);
[[nodiscard]] bool DeleteAttributionRateLimit(RateLimitTable::Scope,
AttributionReport::Id);
[[nodiscard]] base::expected<std::vector<StoredSource::Id>,
RateLimitTable::Error>
GetSourcesToDeactivateForDestinationLimit(const StorableSource& source,
base::Time source_time);
enum class DbCreationPolicy {
kCreateIfAbsent,
kIgnoreIfAbsent,
};
[[nodiscard]] bool LazyInit(DbCreationPolicy creation_policy);
[[nodiscard]] bool DeleteExpiredSources();
int64_t CountActiveSourcesWithSourceOrigin(
const attribution_reporting::SuitableOrigin& origin,
base::Time now);
[[nodiscard]] bool DeactivateSourcesForDestinationLimit(
base::span<const StoredSource::Id>,
base::Time now);
[[nodiscard]] std::optional<AttributionReport::Id> StoreAttributionReport(
StoredSource::Id,
base::Time trigger_time,
base::Time initial_report_time,
const base::Uuid& external_report_id,
std::optional<uint64_t> trigger_debug_key,
const attribution_reporting::SuitableOrigin& context_origin,
const attribution_reporting::SuitableOrigin& reporting_origin,
uint32_t trigger_data,
int64_t priority);
[[nodiscard]] std::optional<AttributionReport::Id> StoreNullReport(
base::Time trigger_time,
base::Time initial_report_time,
const base::Uuid& external_report_id,
std::optional<uint64_t> trigger_debug_key,
const attribution_reporting::SuitableOrigin& context_origin,
const attribution_reporting::SuitableOrigin& reporting_origin,
const std::optional<attribution_reporting::SuitableOrigin>&
coordinator_origin,
const attribution_reporting::AggregatableTriggerConfig& trigger_config,
base::Time fake_source_time);
[[nodiscard]] std::optional<AttributionReport::Id> StoreAggregatableReport(
StoredSource::Id source_id,
base::Time trigger_time,
base::Time initial_report_time,
const base::Uuid& external_report_id,
std::optional<uint64_t> trigger_debug_key,
const attribution_reporting::SuitableOrigin& context_origin,
const attribution_reporting::SuitableOrigin& reporting_origin,
const std::optional<attribution_reporting::SuitableOrigin>&
coordinator_origin,
const attribution_reporting::AggregatableTriggerConfig& trigger_config,
const std::vector<blink::mojom::AggregatableReportHistogramContribution>&
contributions);
[[nodiscard]] bool DeactivateSources(base::span<const StoredSource::Id>);
[[nodiscard]] bool DeleteSources(base::span<const StoredSource::Id>);
bool FindMatchingSourceForTrigger(
const AttributionTrigger& trigger,
base::Time trigger_time,
std::optional<StoredSource::Id>& source_id_to_attribute,
std::vector<StoredSource::Id>& source_ids_to_delete,
std::vector<StoredSource::Id>& source_ids_to_deactivate);
struct StoredSourceData {
StoredSource source;
int num_attributions;
int num_aggregatable_attribution_reports;
};
std::optional<StoredSourceData> ReadSourceToAttribute(
StoredSource::Id source_id);
int64_t CountEventLevelReportsWithDestinationSite(
const net::SchemefulSite& destination);
int64_t CountAggregatableReportsWithDestinationSite(
const net::SchemefulSite& destination);
int64_t CountUniqueDailyReportingOriginsPerReportingSiteForSource(
const net::SchemefulSite& reporting_site,
base::Time source_time);
int64_t
CountUniqueDailyReportingOriginsPerDestinationAndReportingSiteForSource(
const net::SchemefulSite& destination_site,
const net::SchemefulSite& reporting_site,
base::Time source_time);
CreateReportResult::Aggregatable MaybeStoreAggregatableAttributionReportData(
const StoredSource&,
bool has_trigger_context_id,
int remaining_aggregatable_attribution_budget,
int num_aggregatable_attribution_reports,
std::optional<uint64_t> dedup_key,
const std::vector<
attribution_reporting::AggregatableNamedBudgetCandidate>&
trigger_budget_candidates,
CreateReportResult::AggregatableSuccess);
struct ReportIdAndPriority {
AttributionReport::Id id;
int64_t priority;
};
base::expected<std::optional<ReportIdAndPriority>, Error>
GetReportWithMinPriority(StoredSource::Id, base::Time report_time);
[[nodiscard]] bool DeactivateSourceAtEventLevel(StoredSource::Id);
[[nodiscard]] bool IncrementNumAttributions(StoredSource::Id);
[[nodiscard]] bool StoreDedupKey(StoredSource::Id,
uint64_t dedup_key,
AttributionReport::Type);
private:
using ReportCorruptionStatusSet =
base::EnumSet<ReportCorruptionStatus,
ReportCorruptionStatus::kAnyFieldCorrupted,
ReportCorruptionStatus::kMaxValue>;
struct ReportCorruptionStatusSetAndIds;
enum class DbStatus {
kOpen,
kDeferringCreation,
kDeferringOpen,
kClosed,
kClosedDueToCatastrophicError,
};
[[nodiscard]] bool ReadDedupKeys(
StoredSource::Id,
std::vector<uint64_t>& event_level_dedup_keys,
std::vector<uint64_t>& aggregatable_dedup_keys)
VALID_CONTEXT_REQUIRED(sequence_checker_);
base::expected<AttributionReport, ReportCorruptionStatusSetAndIds>
ReadReportFromStatement(sql::Statement&)
VALID_CONTEXT_REQUIRED(sequence_checker_);
base::expected<StoredSourceData, ReportCorruptionStatusSetAndIds>
ReadSourceFromStatement(sql::Statement&)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool DeleteReportInternal(AttributionReport::Id)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool DeleteEventLevelReportsTriggeredLaterThanForSources(
base::span<const StoredSource::Id>,
base::Time source_time) VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool RemoveScopesDataForSource(StoredSource::Id)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool InitializeSchema(bool db_empty)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool CreateSchema() VALID_CONTEXT_REQUIRED(sequence_checker_);
void HandleInitializationFailure(const InitStatus status)
VALID_CONTEXT_REQUIRED(sequence_checker_);
void DatabaseErrorCallback(int extended_error, sql::Statement* stmt);
[[nodiscard]] bool ClearReportsForOriginsInRange(
base::Time delete_begin,
base::Time delete_end,
StoragePartition::StorageKeyMatcherFunction filter,
std::vector<StoredSource::Id>& source_ids_to_delete,
int& num_event_reports_deleted,
int& num_aggregatable_reports_deleted)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool ClearReportsForSourceIds(
base::span<const StoredSource::Id>,
int& num_event_reports_deleted,
int& num_aggregatable_reports_deleted)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool AdjustBudgetConsumedForSource(
StoredSource::Id source_id,
bool has_trigger_context_id,
int additional_budget_consumed,
const StoredSource::AggregatableNamedBudgets*)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] std::optional<AttributionReport::Id> StoreAttributionReport(
int64_t source_id,
base::Time trigger_time,
base::Time initial_report_time,
const base::Uuid& external_report_id,
std::optional<uint64_t> trigger_debug_key,
const attribution_reporting::SuitableOrigin& context_origin,
const attribution_reporting::SuitableOrigin& reporting_origin,
AttributionReport::Type,
const std::string& serialized_metadata)
VALID_CONTEXT_REQUIRED(sequence_checker_);
[[nodiscard]] bool AdjustAggregatableDebugSourceData(
StoredSource::Id,
int additional_budget_consumed) VALID_CONTEXT_REQUIRED(sequence_checker_);
const base::FilePath path_to_database_;
std::optional<DbStatus> db_status_ GUARDED_BY_CONTEXT(sequence_checker_);
sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_);
raw_ptr<AttributionResolverDelegate> delegate_
GUARDED_BY_CONTEXT(sequence_checker_);
RateLimitTable rate_limit_table_ GUARDED_BY_CONTEXT(sequence_checker_);
AggregatableDebugRateLimitTable aggregatable_debug_rate_limit_table_
GUARDED_BY_CONTEXT(sequence_checker_);
OsRegistrationsTable os_registrations_table_
GUARDED_BY_CONTEXT(sequence_checker_);
SEQUENCE_CHECKER(sequence_checker_);
};
}
#endif