blob: f9ff990bc22f361254fd8f72e8c877b8e9a62466 [file] [log] [blame]
// 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 "content/browser/conversions/conversion_storage_delegate_impl.h"
#include <algorithm>
namespace content {
ConversionStorageDelegateImpl::ConversionStorageDelegateImpl(bool debug_mode)
: debug_mode_(debug_mode) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
const StorableImpression&
ConversionStorageDelegateImpl::GetImpressionToAttribute(
const std::vector<StorableImpression>& impressions) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!impressions.empty());
// Chooses the impression with the largest priority value. In the case of
// ties, impression_time is used to tie break.
//
// Note that impressions which do not get a priority get defaulted to 0,
// meaning they can be attributed over impressions which set a negative
// priority.
return *std::max_element(
impressions.begin(), impressions.end(),
[](const StorableImpression& a, const StorableImpression& b) {
if (a.priority() < b.priority())
return true;
if (a.priority() > b.priority())
return false;
return a.impression_time() < b.impression_time();
});
}
void ConversionStorageDelegateImpl::ProcessNewConversionReport(
ConversionReport& report) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
report.report_time = GetReportTimeForConversion(report);
}
int ConversionStorageDelegateImpl::GetMaxConversionsPerImpression(
StorableImpression::SourceType source_type) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (source_type) {
case StorableImpression::SourceType::kNavigation:
return 3;
case StorableImpression::SourceType::kEvent:
return 1;
}
}
int ConversionStorageDelegateImpl::GetMaxImpressionsPerOrigin() const {
return 1024;
}
int ConversionStorageDelegateImpl::GetMaxConversionsPerOrigin() const {
return 1024;
}
ConversionStorage::Delegate::RateLimitConfig
ConversionStorageDelegateImpl::GetRateLimits() const {
// TODO(csharrison): Finalize max_attributions_per_window value.
return {
.time_window = base::TimeDelta::FromDays(30),
.max_attributions_per_window = 100,
};
}
base::Time ConversionStorageDelegateImpl::GetReportTimeForConversion(
const ConversionReport& report) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// |report.report_time| is roughly ~now, for newly created conversion
// reports. If in debug mode, the report should be sent immediately.
if (debug_mode_)
return report.report_time;
base::TimeDelta expiry_deadline =
report.impression.expiry_time() - report.impression.impression_time();
constexpr base::TimeDelta kMinExpiryDeadline = base::TimeDelta::FromDays(2);
if (expiry_deadline < kMinExpiryDeadline)
expiry_deadline = kMinExpiryDeadline;
// After the initial impression, a schedule of reporting windows and deadlines
// associated with that impression begins. The time between impression time
// and impression expiry is split into multiple reporting windows. At the end
// of each window, the browser will send all scheduled reports for that
// impression.
//
// Each reporting window has a deadline and only conversions registered before
// that deadline are sent in that window. Each deadline is one hour prior to
// the window report time. The deadlines relative to impression time are <2
// days minus 1 hour, 7 days minus 1 hour, impression expiry>. The impression
// expiry window is only used for conversions that occur after the 7 day
// deadline. For example, a conversion which happens one hour after an
// impression with an expiry of two hours, is still reported in the 2 day
// window.
//
// Note that only navigation (not event) sources have early reporting
// deadlines.
constexpr base::TimeDelta kWindowDeadlineOffset =
base::TimeDelta::FromHours(1);
std::vector<base::TimeDelta> early_deadlines;
switch (report.impression.source_type()) {
case StorableImpression::SourceType::kNavigation:
early_deadlines = {base::TimeDelta::FromDays(2) - kWindowDeadlineOffset,
base::TimeDelta::FromDays(7) - kWindowDeadlineOffset};
break;
case StorableImpression::SourceType::kEvent:
early_deadlines = {};
break;
}
base::TimeDelta deadline_to_use = expiry_deadline;
// Given a conversion report that was created at |report.report_time|, find
// the first applicable reporting window this conversion should be reported
// at.
for (base::TimeDelta early_deadline : early_deadlines) {
// If this window is valid for the conversion, use it. |report.report_time|
// is roughly ~now, as the conversion time is used as the default value for
// newly created reports that have not had a report time set.
if (report.impression.impression_time() + early_deadline >=
report.report_time &&
early_deadline < deadline_to_use) {
deadline_to_use = early_deadline;
break;
}
}
// Valid conversion reports should always have a valid reporting deadline.
DCHECK(!deadline_to_use.is_zero());
return report.impression.impression_time() + deadline_to_use +
kWindowDeadlineOffset;
}
} // namespace content