Reporting / NEL: Allow limited NEL reports on Reporting uploads.
Change-Id: If7751d0316ac54e8c2e961c5b4e0385f1c6107a6
Reviewed-on: https://chromium-review.googlesource.com/978301
Commit-Queue: Julia Tuttle <[email protected]>
Reviewed-by: Asanka Herath <[email protected]>
Reviewed-by: Bernhard Bauer <[email protected]>
Cr-Commit-Position: refs/heads/master@{#546894}
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index f27f7a8..8d73eaa3 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -977,7 +977,8 @@
void QueueReport(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body) override {
+ std::unique_ptr<const base::Value> body,
+ int depth) override {
NOTREACHED();
}
@@ -994,9 +995,9 @@
last_origin_filter_ = origin_filter;
}
- bool RequestIsUpload(const net::URLRequest& request) override {
+ int GetUploadDepth(const net::URLRequest& request) override {
NOTREACHED();
- return true;
+ return 0;
}
const net::ReportingPolicy& GetPolicy() const override {
diff --git a/content/browser/net/reporting_service_proxy.cc b/content/browser/net/reporting_service_proxy.cc
index 99f7d73..97fc3ec3 100644
--- a/content/browser/net/reporting_service_proxy.cc
+++ b/content/browser/net/reporting_service_proxy.cc
@@ -116,7 +116,10 @@
return;
}
- reporting_service->QueueReport(url, group, type, std::move(body));
+ // Depth is only non-zero for NEL reports, and those can't come from the
+ // renderer.
+ reporting_service->QueueReport(url, group, type, std::move(body),
+ /* depth= */ 0);
}
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index b838000..6fdbcce 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -118,11 +118,6 @@
return request.status_code >= 400 && request.status_code < 600;
}
-bool RequestWasSuccessful(
- const NetworkErrorLoggingService::RequestDetails& request) {
- return request.type == OK && !IsHttpError(request);
-}
-
enum class HeaderOutcome {
DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE = 0,
DISCARDED_INVALID_SSL_INFO = 1,
@@ -234,28 +229,35 @@
return;
}
- std::string type_string;
- if (!GetTypeFromNetError(details.type, &type_string)) {
- RecordRequestOutcome(RequestOutcome::DISCARDED_UNMAPPED_ERROR);
- return;
- }
-
+ Error type = details.type;
// It is expected for Reporting uploads to terminate with ERR_ABORTED, since
// the ReportingUploader cancels them after receiving the response code and
// headers.
- //
- // (This check would go earlier, but the histogram bucket will be more
- // meaningful if it only includes reports that otherwise could have been
- // uploaded.)
- if (details.is_reporting_upload && details.type == ERR_ABORTED) {
- RecordRequestOutcome(RequestOutcome::DISCARDED_REPORTING_UPLOAD);
+ if (details.reporting_upload_depth > 0 && type == ERR_ABORTED) {
+ // TODO(juliatuttle): Modify ReportingUploader to drain successful uploads
+ // instead of aborting them, so NEL can properly report on aborted
+ // requests.
+ type = OK;
+ }
+
+ std::string type_string;
+ if (!GetTypeFromNetError(type, &type_string)) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_UNMAPPED_ERROR);
return;
}
if (IsHttpError(details))
type_string = kHttpErrorType;
- bool success = RequestWasSuccessful(details);
+ // This check would go earlier, but the histogram bucket will be more
+ // meaningful if it only includes reports that otherwise could have been
+ // uploaded.
+ if (details.reporting_upload_depth > kMaxNestedReportDepth) {
+ RecordRequestOutcome(RequestOutcome::DISCARDED_REPORTING_UPLOAD);
+ return;
+ }
+
+ bool success = (type == OK) && !IsHttpError(details);
double sampling_fraction =
success ? policy->success_fraction : policy->failure_fraction;
if (base::RandDouble() >= sampling_fraction) {
@@ -267,7 +269,8 @@
reporting_service_->QueueReport(
details.uri, policy->report_to, kReportType,
- CreateReportBody(type_string, sampling_fraction, details));
+ CreateReportBody(type_string, sampling_fraction, details),
+ details.reporting_upload_depth);
RecordRequestOutcome(RequestOutcome::QUEUED);
}
@@ -500,6 +503,15 @@
const char NetworkErrorLoggingService::kHeaderName[] = "NEL";
const char NetworkErrorLoggingService::kReportType[] = "network-error";
+
+// Allow NEL reports on regular requests, plus NEL reports on Reporting uploads
+// containing only regular requests, but do not allow NEL reports on Reporting
+// uploads containing Reporting uploads.
+//
+// This prevents origins from building purposefully-broken Reporting endpoints
+// that generate new NEL reports to bypass the age limit on Reporting reports.
+const int NetworkErrorLoggingService::kMaxNestedReportDepth = 1;
+
const char NetworkErrorLoggingService::kUriKey[] = "uri";
const char NetworkErrorLoggingService::kReferrerKey[] = "referrer";
const char NetworkErrorLoggingService::kSamplingFractionKey[] =
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h
index c41ae83..e63ece2 100644
--- a/net/network_error_logging/network_error_logging_service.h
+++ b/net/network_error_logging/network_error_logging_service.h
@@ -56,13 +56,22 @@
base::TimeDelta elapsed_time;
Error type;
- bool is_reporting_upload;
+ // Upload nesting depth of this request.
+ //
+ // If the request is not a Reporting upload, the depth is 0.
+ //
+ // If the request is a Reporting upload, the depth is the max of the depth
+ // of the requests reported within it plus 1. (Non-NEL reports are
+ // considered to have depth 0.)
+ int reporting_upload_depth;
};
static const char kHeaderName[];
static const char kReportType[];
+ static const int kMaxNestedReportDepth;
+
// Keys for data included in report bodies. Exposed for tests.
static const char kUriKey[];
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 0cc3ab42..79d9681 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -35,13 +35,19 @@
: url(other.url),
group(other.group),
type(other.type),
- body(std::move(other.body)) {}
+ body(std::move(other.body)),
+ depth(other.depth) {}
Report(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body)
- : url(url), group(group), type(type), body(std::move(body)) {}
+ std::unique_ptr<const base::Value> body,
+ int depth)
+ : url(url),
+ group(group),
+ type(type),
+ body(std::move(body)),
+ depth(depth) {}
~Report() = default;
@@ -49,6 +55,7 @@
std::string group;
std::string type;
std::unique_ptr<const base::Value> body;
+ int depth;
private:
DISALLOW_COPY(Report);
@@ -65,8 +72,9 @@
void QueueReport(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body) override {
- reports_.push_back(Report(url, group, type, std::move(body)));
+ std::unique_ptr<const base::Value> body,
+ int depth) override {
+ reports_.push_back(Report(url, group, type, std::move(body), depth));
}
void ProcessHeader(const GURL& url,
@@ -80,9 +88,9 @@
NOTREACHED();
}
- bool RequestIsUpload(const URLRequest& request) override {
+ int GetUploadDepth(const URLRequest& request) override {
NOTREACHED();
- return true;
+ return 0;
}
const ReportingPolicy& GetPolicy() const override {
@@ -130,7 +138,7 @@
details.status_code = status_code;
details.elapsed_time = base::TimeDelta::FromSeconds(1);
details.type = error_type;
- details.is_reporting_upload = false;
+ details.reporting_upload_depth = 0;
return details;
}
@@ -240,6 +248,7 @@
EXPECT_EQ(kUrl_, reports()[0].url);
EXPECT_EQ(kGroup_, reports()[0].group);
EXPECT_EQ(kType_, reports()[0].type);
+ EXPECT_EQ(0, reports()[0].depth);
const base::DictionaryValue* body;
ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
@@ -273,6 +282,7 @@
EXPECT_EQ(kUrl_, reports()[0].url);
EXPECT_EQ(kGroup_, reports()[0].group);
EXPECT_EQ(kType_, reports()[0].type);
+ EXPECT_EQ(0, reports()[0].depth);
const base::DictionaryValue* body;
ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
@@ -306,6 +316,7 @@
EXPECT_EQ(kUrl_, reports()[0].url);
EXPECT_EQ(kGroup_, reports()[0].group);
EXPECT_EQ(kType_, reports()[0].type);
+ EXPECT_EQ(0, reports()[0].depth);
const base::DictionaryValue* body;
ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
@@ -508,5 +519,31 @@
ASSERT_EQ(1u, reports().size());
}
+TEST_F(NetworkErrorLoggingServiceTest, Nested) {
+ service()->OnHeader(kOrigin_, kHeader_);
+
+ NetworkErrorLoggingService::RequestDetails details =
+ MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED);
+ details.reporting_upload_depth =
+ NetworkErrorLoggingService::kMaxNestedReportDepth;
+ service()->OnRequest(details);
+
+ ASSERT_EQ(1u, reports().size());
+ EXPECT_EQ(NetworkErrorLoggingService::kMaxNestedReportDepth,
+ reports()[0].depth);
+}
+
+TEST_F(NetworkErrorLoggingServiceTest, NestedTooDeep) {
+ service()->OnHeader(kOrigin_, kHeader_);
+
+ NetworkErrorLoggingService::RequestDetails details =
+ MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED);
+ details.reporting_upload_depth =
+ NetworkErrorLoggingService::kMaxNestedReportDepth + 1;
+ service()->OnRequest(details);
+
+ EXPECT_TRUE(reports().empty());
+}
+
} // namespace
} // namespace net
diff --git a/net/reporting/reporting_browsing_data_remover_unittest.cc b/net/reporting/reporting_browsing_data_remover_unittest.cc
index 3d8d10d81..7e720e98 100644
--- a/net/reporting/reporting_browsing_data_remover_unittest.cc
+++ b/net/reporting/reporting_browsing_data_remover_unittest.cc
@@ -41,7 +41,7 @@
void AddReport(const GURL& url) {
cache()->AddReport(url, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
}
diff --git a/net/reporting/reporting_cache.cc b/net/reporting/reporting_cache.cc
index 14a61c2..4d4a1d0 100644
--- a/net/reporting/reporting_cache.cc
+++ b/net/reporting/reporting_cache.cc
@@ -67,10 +67,11 @@
const std::string& group,
const std::string& type,
std::unique_ptr<const base::Value> body,
+ int depth,
base::TimeTicks queued,
int attempts) override {
auto report = std::make_unique<ReportingReport>(
- url, group, type, std::move(body), queued, attempts);
+ url, group, type, std::move(body), depth, queued, attempts);
auto inserted =
reports_.insert(std::make_pair(report.get(), std::move(report)));
diff --git a/net/reporting/reporting_cache.h b/net/reporting/reporting_cache.h
index e948748..a395f7f 100644
--- a/net/reporting/reporting_cache.h
+++ b/net/reporting/reporting_cache.h
@@ -47,6 +47,7 @@
const std::string& group,
const std::string& type,
std::unique_ptr<const base::Value> body,
+ int depth,
base::TimeTicks queued,
int attempts) = 0;
diff --git a/net/reporting/reporting_cache_unittest.cc b/net/reporting/reporting_cache_unittest.cc
index 6e447fcf..de65ee4 100644
--- a/net/reporting/reporting_cache_unittest.cc
+++ b/net/reporting/reporting_cache_unittest.cc
@@ -94,7 +94,7 @@
EXPECT_TRUE(reports.empty());
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
EXPECT_EQ(1, observer()->cache_update_count());
cache()->GetReports(&reports);
@@ -128,9 +128,9 @@
TEST_F(ReportingCacheTest, RemoveAllReports) {
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
EXPECT_EQ(2, observer()->cache_update_count());
std::vector<const ReportingReport*> reports;
@@ -146,7 +146,7 @@
TEST_F(ReportingCacheTest, RemovePendingReports) {
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
EXPECT_EQ(1, observer()->cache_update_count());
std::vector<const ReportingReport*> reports;
@@ -177,7 +177,7 @@
TEST_F(ReportingCacheTest, RemoveAllPendingReports) {
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
EXPECT_EQ(1, observer()->cache_update_count());
std::vector<const ReportingReport*> reports;
@@ -410,7 +410,7 @@
// Enqueue the maximum number of reports, spaced apart in time.
for (size_t i = 0; i < max_report_count; ++i) {
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
tick_clock()->Advance(base::TimeDelta::FromMinutes(1));
}
@@ -418,7 +418,7 @@
// Add one more report to force the cache to evict one.
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
// Make sure the cache evicted a report to make room for the new one, and make
// sure the report evicted was the earliest-queued one.
@@ -438,7 +438,7 @@
// Enqueue the maximum number of reports, spaced apart in time.
for (size_t i = 0; i < max_report_count; ++i) {
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
tick_clock()->Advance(base::TimeDelta::FromMinutes(1));
}
@@ -452,7 +452,7 @@
// Add one more report to force the cache to evict one. Since the cache has
// only pending reports, it will be forced to evict the *new* report!
cache()->AddReport(kUrl1_, kGroup1_, kType_,
- std::make_unique<base::DictionaryValue>(), kNow_, 0);
+ std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
// Make sure the cache evicted a report, and make sure the report evicted was
// the new, non-pending one.
diff --git a/net/reporting/reporting_delivery_agent.cc b/net/reporting/reporting_delivery_agent.cc
index 7a3ab2e..7419430 100644
--- a/net/reporting/reporting_delivery_agent.cc
+++ b/net/reporting/reporting_delivery_agent.cc
@@ -180,11 +180,16 @@
std::string json;
SerializeReports(reports, tick_clock()->NowTicks(), &json);
- for (const ReportingReport* report : reports)
+ int max_depth = 0;
+ for (const ReportingReport* report : reports) {
undelivered_reports.erase(report);
+ if (report->depth > max_depth)
+ max_depth = report->depth;
+ }
+ // TODO: Calculate actual max depth.
uploader()->StartUpload(
- endpoint, json,
+ endpoint, json, max_depth,
base::BindOnce(
&ReportingDeliveryAgentImpl::OnUploadComplete,
weak_factory_.GetWeakPtr(),
diff --git a/net/reporting/reporting_delivery_agent_unittest.cc b/net/reporting/reporting_delivery_agent_unittest.cc
index c5b1a418..afd1f89 100644
--- a/net/reporting/reporting_delivery_agent_unittest.cc
+++ b/net/reporting/reporting_delivery_agent_unittest.cc
@@ -64,7 +64,7 @@
body.SetString("key", "value");
SetClient(kOrigin_, kEndpoint_, kGroup_);
- cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(),
+ cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
tick_clock()->NowTicks(), 0);
tick_clock()->Advance(base::TimeDelta::FromMilliseconds(kAgeMillis));
@@ -103,7 +103,7 @@
TEST_F(ReportingDeliveryAgentTest, FailedUpload) {
SetClient(kOrigin_, kEndpoint_, kGroup_);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -137,7 +137,7 @@
body.SetString("key", "value");
SetClient(kOrigin_, kEndpoint_, kGroup_);
- cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(),
+ cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
tick_clock()->NowTicks(), 0);
tick_clock()->Advance(base::TimeDelta::FromMilliseconds(kAgeMillis));
@@ -165,7 +165,7 @@
ASSERT_TRUE(FindClientInCache(cache(), kDifferentOrigin, kEndpoint_));
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -194,7 +194,7 @@
TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) {
SetClient(kOrigin_, kEndpoint_, kGroup_);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -233,7 +233,7 @@
SetClient(kOrigin_, kEndpoint_, kGroup_);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -277,10 +277,10 @@
SetClient(kDifferentOrigin, kEndpoint_, kGroup_);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
cache()->AddReport(kDifferentUrl, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -303,7 +303,7 @@
SetClient(kDifferentOrigin, kEndpoint_, kGroup_);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -311,7 +311,7 @@
EXPECT_EQ(1u, pending_uploads().size());
cache()->AddReport(kDifferentUrl, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -339,7 +339,7 @@
SetClient(kOrigin_, kDifferentEndpoint, kGroup_);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -347,7 +347,7 @@
EXPECT_EQ(1u, pending_uploads().size());
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
@@ -375,10 +375,10 @@
SetClient(kOrigin_, kDifferentEndpoint, kDifferentGroup);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
cache()->AddReport(kUrl_, kDifferentGroup, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(delivery_timer()->IsRunning());
diff --git a/net/reporting/reporting_garbage_collector_unittest.cc b/net/reporting/reporting_garbage_collector_unittest.cc
index 3aac7abf..5ae177b 100644
--- a/net/reporting/reporting_garbage_collector_unittest.cc
+++ b/net/reporting/reporting_garbage_collector_unittest.cc
@@ -41,7 +41,7 @@
EXPECT_FALSE(garbage_collection_timer()->IsRunning());
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
EXPECT_TRUE(garbage_collection_timer()->IsRunning());
@@ -53,7 +53,7 @@
TEST_F(ReportingGarbageCollectorTest, Report) {
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
garbage_collection_timer()->Fire();
@@ -62,7 +62,7 @@
TEST_F(ReportingGarbageCollectorTest, ExpiredReport) {
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
tick_clock()->Advance(2 * policy().max_report_age);
garbage_collection_timer()->Fire();
@@ -72,7 +72,7 @@
TEST_F(ReportingGarbageCollectorTest, FailedReport) {
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
std::vector<const ReportingReport*> reports;
diff --git a/net/reporting/reporting_network_change_observer_unittest.cc b/net/reporting/reporting_network_change_observer_unittest.cc
index ae35fbda8..db1aabc 100644
--- a/net/reporting/reporting_network_change_observer_unittest.cc
+++ b/net/reporting/reporting_network_change_observer_unittest.cc
@@ -65,7 +65,7 @@
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
SetClient();
ASSERT_EQ(1u, report_count());
@@ -84,7 +84,7 @@
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
SetClient();
ASSERT_EQ(1u, report_count());
@@ -103,7 +103,7 @@
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
SetClient();
ASSERT_EQ(1u, report_count());
@@ -122,7 +122,7 @@
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>(),
+ std::make_unique<base::DictionaryValue>(), 0,
tick_clock()->NowTicks(), 0);
SetClient();
ASSERT_EQ(1u, report_count());
diff --git a/net/reporting/reporting_report.cc b/net/reporting/reporting_report.cc
index 2a594841..c6dd8204 100644
--- a/net/reporting/reporting_report.cc
+++ b/net/reporting/reporting_report.cc
@@ -28,12 +28,14 @@
const std::string& group,
const std::string& type,
std::unique_ptr<const base::Value> body,
+ int depth,
base::TimeTicks queued,
int attempts)
: url(url),
group(group),
type(type),
body(std::move(body)),
+ depth(depth),
queued(queued),
attempts(attempts),
outcome(Outcome::UNKNOWN),
diff --git a/net/reporting/reporting_report.h b/net/reporting/reporting_report.h
index e7fba5d..196be9e 100644
--- a/net/reporting/reporting_report.h
+++ b/net/reporting/reporting_report.h
@@ -41,6 +41,7 @@
const std::string& group,
const std::string& type,
std::unique_ptr<const base::Value> body,
+ int depth,
base::TimeTicks queued,
int attempts);
~ReportingReport();
@@ -64,6 +65,11 @@
// The body of the report. (Included in the delivered report.)
std::unique_ptr<const base::Value> body;
+ // How many uploads deep the related request was: 0 if the related request was
+ // not an upload (or there was no related request), or n+1 if it was an upload
+ // reporting on requests of at most depth n.
+ int depth;
+
// When the report was queued. (Included in the delivered report as an age
// relative to the time of the delivery attempt.)
base::TimeTicks queued;
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc
index 24be577..ce1efb0 100644
--- a/net/reporting/reporting_service.cc
+++ b/net/reporting/reporting_service.cc
@@ -36,14 +36,15 @@
void QueueReport(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body) override {
+ std::unique_ptr<const base::Value> body,
+ int depth) override {
DCHECK(context_);
DCHECK(context_->delegate());
if (!context_->delegate()->CanQueueReport(url::Origin::Create(url)))
return;
- context_->cache()->AddReport(url, group, type, std::move(body),
+ context_->cache()->AddReport(url, group, type, std::move(body), depth,
context_->tick_clock()->NowTicks(), 0);
}
@@ -64,8 +65,8 @@
context_->cache(), data_type_mask, origin_filter);
}
- bool RequestIsUpload(const URLRequest& request) override {
- return context_->uploader()->RequestIsUpload(request);
+ int GetUploadDepth(const URLRequest& request) override {
+ return context_->uploader()->GetUploadDepth(request);
}
const ReportingPolicy& GetPolicy() const override {
diff --git a/net/reporting/reporting_service.h b/net/reporting/reporting_service.h
index 37958702..b165cdcd 100644
--- a/net/reporting/reporting_service.h
+++ b/net/reporting/reporting_service.h
@@ -53,7 +53,8 @@
virtual void QueueReport(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body) = 0;
+ std::unique_ptr<const base::Value> body,
+ int depth) = 0;
// Processes a Report-To header. |url| is the URL that originated the header;
// |header_value| is the normalized value of the Report-To header.
@@ -66,9 +67,9 @@
int data_type_mask,
const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0;
- // Checks whether |request| is a Reporting upload, to avoid loops of reporting
- // about report uploads.
- virtual bool RequestIsUpload(const URLRequest& request) = 0;
+ // Checks how many uploads deep |request| is: 0 if it's not an upload, n+1 if
+ // it's an upload reporting on requests of at most depth n.
+ virtual int GetUploadDepth(const URLRequest& request) = 0;
virtual const ReportingPolicy& GetPolicy() const = 0;
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc
index 6b9f303..c0dd7fe5 100644
--- a/net/reporting/reporting_service_unittest.cc
+++ b/net/reporting/reporting_service_unittest.cc
@@ -48,7 +48,7 @@
TEST_F(ReportingServiceTest, QueueReport) {
service()->QueueReport(kUrl_, kGroup_, kType_,
- std::make_unique<base::DictionaryValue>());
+ std::make_unique<base::DictionaryValue>(), 0);
std::vector<const ReportingReport*> reports;
context()->cache()->GetReports(&reports);
diff --git a/net/reporting/reporting_test_util.cc b/net/reporting/reporting_test_util.cc
index e998b58..e87f889 100644
--- a/net/reporting/reporting_test_util.cc
+++ b/net/reporting/reporting_test_util.cc
@@ -46,7 +46,7 @@
~PendingUploadImpl() override = default;
- // PendingUpload implementationP:
+ // PendingUpload implementation:
const GURL& url() const override { return url_; }
const std::string& json() const override { return json_; }
std::unique_ptr<base::Value> GetValue() const override {
@@ -100,15 +100,16 @@
void TestReportingUploader::StartUpload(const GURL& url,
const std::string& json,
+ int max_depth,
UploadCallback callback) {
pending_uploads_.push_back(std::make_unique<PendingUploadImpl>(
url, json, std::move(callback),
base::BindOnce(&ErasePendingUpload, &pending_uploads_)));
}
-bool TestReportingUploader::RequestIsUpload(const URLRequest& request) {
+int TestReportingUploader::GetUploadDepth(const URLRequest& request) {
NOTIMPLEMENTED();
- return true;
+ return 0;
}
TestReportingDelegate::TestReportingDelegate()
diff --git a/net/reporting/reporting_test_util.h b/net/reporting/reporting_test_util.h
index ff387ecf4..296827b 100644
--- a/net/reporting/reporting_test_util.h
+++ b/net/reporting/reporting_test_util.h
@@ -73,9 +73,10 @@
void StartUpload(const GURL& url,
const std::string& json,
+ int max_depth,
UploadCallback callback) override;
- bool RequestIsUpload(const URLRequest& request) override;
+ int GetUploadDepth(const URLRequest& request) override;
private:
std::vector<std::unique_ptr<PendingUpload>> pending_uploads_;
diff --git a/net/reporting/reporting_uploader.cc b/net/reporting/reporting_uploader.cc
index 2353726..9cd1273 100644
--- a/net/reporting/reporting_uploader.cc
+++ b/net/reporting/reporting_uploader.cc
@@ -27,6 +27,10 @@
class UploadUserData : public base::SupportsUserData::Data {
public:
static const void* const kUserDataKey;
+
+ UploadUserData(int depth) : depth(depth) {}
+
+ int depth;
};
// SetUserData needs a unique const void* to serve as the key, so create a const
@@ -77,6 +81,7 @@
void StartUpload(const GURL& url,
const std::string& json,
+ int max_depth,
UploadCallback callback) override {
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("reporting", R"(
@@ -116,7 +121,7 @@
ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
request->SetUserData(UploadUserData::kUserDataKey,
- std::make_unique<UploadUserData>());
+ std::make_unique<UploadUserData>(max_depth));
// This inherently sets mode = "no-cors", but that doesn't matter, because
// the origins that are included in the upload don't actually get to see
@@ -132,8 +137,10 @@
}
// static
- bool RequestIsUpload(const net::URLRequest& request) override {
- return request.GetUserData(UploadUserData::kUserDataKey);
+ int GetUploadDepth(const net::URLRequest& request) override {
+ UploadUserData* data = static_cast<UploadUserData*>(
+ request.GetUserData(UploadUserData::kUserDataKey));
+ return data ? data->depth + 1 : 0;
}
// URLRequest::Delegate implementation:
diff --git a/net/reporting/reporting_uploader.h b/net/reporting/reporting_uploader.h
index f6c65c7..b17c0c49 100644
--- a/net/reporting/reporting_uploader.h
+++ b/net/reporting/reporting_uploader.h
@@ -34,10 +34,11 @@
// |url|, and calls |callback| when complete (whether successful or not).
virtual void StartUpload(const GURL& url,
const std::string& json,
+ int max_depth,
UploadCallback callback) = 0;
// Returns whether |request| is an upload request sent by this uploader.
- virtual bool RequestIsUpload(const URLRequest& request) = 0;
+ virtual int GetUploadDepth(const URLRequest& request) = 0;
// Creates a real implementation of |ReportingUploader| that uploads reports
// using |context|.
diff --git a/net/reporting/reporting_uploader_unittest.cc b/net/reporting/reporting_uploader_unittest.cc
index 9fcda4d..e417b08d 100644
--- a/net/reporting/reporting_uploader_unittest.cc
+++ b/net/reporting/reporting_uploader_unittest.cc
@@ -109,7 +109,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
}
@@ -118,7 +119,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
@@ -130,7 +132,7 @@
ASSERT_TRUE(server_.ShutdownAndWaitUntilComplete());
TestUploadCallback callback;
- uploader_->StartUpload(url, kUploadBody, callback.callback());
+ uploader_->StartUpload(url, kUploadBody, 0, callback.callback());
callback.WaitForCall();
EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -141,7 +143,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -153,7 +156,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -165,7 +169,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
EXPECT_EQ(ReportingUploader::Outcome::REMOVE_ENDPOINT, callback.outcome());
@@ -207,7 +212,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
EXPECT_TRUE(followed);
@@ -228,7 +234,8 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody, callback.callback());
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
+ callback.callback());
callback.WaitForCall();
EXPECT_FALSE(followed);
@@ -254,7 +261,7 @@
ASSERT_TRUE(cookie_callback.result());
TestUploadCallback upload_callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody,
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
upload_callback.callback());
upload_callback.WaitForCall();
}
@@ -274,7 +281,7 @@
ASSERT_TRUE(server_.Start());
TestUploadCallback upload_callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody,
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
upload_callback.callback());
upload_callback.WaitForCall();
@@ -312,7 +319,7 @@
{
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody,
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
callback.callback());
callback.WaitForCall();
}
@@ -320,7 +327,7 @@
{
TestUploadCallback callback;
- uploader_->StartUpload(server_.GetURL("/"), kUploadBody,
+ uploader_->StartUpload(server_.GetURL("/"), kUploadBody, 0,
callback.callback());
callback.WaitForCall();
}
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 8e18063..cd187ce 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -1196,9 +1196,12 @@
base::TimeTicks::Now() - load_timing_info_.request_start;
details.type = status().ToNetError();
- details.is_reporting_upload =
- context()->reporting_service() &&
- context()->reporting_service()->RequestIsUpload(*this);
+ if (context()->reporting_service()) {
+ details.reporting_upload_depth =
+ context()->reporting_service()->GetUploadDepth(*this);
+ } else {
+ details.reporting_upload_depth = 0;
+ }
service->OnRequest(details);
}
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 023a29af..dc599e8 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -7116,7 +7116,8 @@
void QueueReport(const GURL& url,
const std::string& group,
const std::string& type,
- std::unique_ptr<const base::Value> body) override {
+ std::unique_ptr<const base::Value> body,
+ int depth) override {
NOTIMPLEMENTED();
}
@@ -7131,9 +7132,9 @@
NOTIMPLEMENTED();
}
- bool RequestIsUpload(const URLRequest& request) override {
+ int GetUploadDepth(const URLRequest& request) override {
NOTIMPLEMENTED();
- return true;
+ return 0;
}
const ReportingPolicy& GetPolicy() const override {