blob: 2f101af198b2f5f8aacd1142000d243cfc16df5f [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"
namespace content {
ConversionStorageDelegateImpl::ConversionStorageDelegateImpl(bool debug_mode)
: debug_mode_(debug_mode) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
void ConversionStorageDelegateImpl::ProcessNewConversionReports(
std::vector<ConversionReport>* reports) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!reports->empty());
ConversionReport* last_report = &(reports->at(0));
// Assign attribution credits to each report that will be sent at report time.
// This performs "last click" attribution which assigns the report
// for the most recent impression a credit of 100, and the rest a credit of 0.
for (ConversionReport& report : *reports) {
report.report_time = GetReportTimeForConversion(report);
report.attribution_credit = 0;
if (report.impression.impression_time() >
last_report->impression.impression_time())
last_report = &report;
}
last_report->attribution_credit = 100;
}
int ConversionStorageDelegateImpl::GetMaxConversionsPerImpression() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return 3;
}
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;
// 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.
constexpr base::TimeDelta kWindowDeadlineOffset =
base::TimeDelta::FromHours(1);
base::TimeDelta expiry_deadline =
report.impression.expiry_time() - report.impression.impression_time();
const base::TimeDelta kReportingWindowDeadlines[] = {
base::TimeDelta::FromDays(2) - kWindowDeadlineOffset,
base::TimeDelta::FromDays(7) - kWindowDeadlineOffset, expiry_deadline};
base::TimeDelta deadline_to_use;
// 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 report_window_deadline : kReportingWindowDeadlines) {
// 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() + report_window_deadline >=
report.report_time) {
deadline_to_use = report_window_deadline;
break;
}
}
// Valid conversion reports should always have a valid reporting deadline.
DCHECK(!deadline_to_use.is_zero());
// If the expiry deadline falls after the first window, but before another
// window, use it instead. For example, if expiry is at 3 days, we can send
// reports at the 2 day deadline and the expiry deadline instead of at the 7
// day deadline.
if (expiry_deadline > kReportingWindowDeadlines[0] &&
expiry_deadline < deadline_to_use) {
deadline_to_use = expiry_deadline;
}
return report.impression.impression_time() + deadline_to_use +
kWindowDeadlineOffset;
}
} // namespace content