summaryrefslogtreecommitdiff
path: root/chromium/net/reporting
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-03 13:42:47 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:27:51 +0000
commit8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (patch)
treed29d987c4d7b173cf853279b79a51598f104b403 /chromium/net/reporting
parent830c9e163d31a9180fadca926b3e1d7dfffb5021 (diff)
downloadqtwebengine-chromium-8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec.tar.gz
BASELINE: Update Chromium to 66.0.3359.156
Change-Id: I0c9831ad39911a086b6377b16f995ad75a51e441 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/net/reporting')
-rw-r--r--chromium/net/reporting/reporting_cache.cc15
-rw-r--r--chromium/net/reporting/reporting_cache.h15
-rw-r--r--chromium/net/reporting/reporting_delegate.cc24
-rw-r--r--chromium/net/reporting/reporting_delegate.h27
-rw-r--r--chromium/net/reporting/reporting_delivery_agent.cc51
-rw-r--r--chromium/net/reporting/reporting_delivery_agent_unittest.cc70
-rw-r--r--chromium/net/reporting/reporting_feature.cc11
-rw-r--r--chromium/net/reporting/reporting_feature.h17
-rw-r--r--chromium/net/reporting/reporting_header_parser.cc168
-rw-r--r--chromium/net/reporting/reporting_header_parser.h9
-rw-r--r--chromium/net/reporting/reporting_header_parser_fuzzer.cc27
-rw-r--r--chromium/net/reporting/reporting_header_parser_unittest.cc97
-rw-r--r--chromium/net/reporting/reporting_network_change_observer.cc4
-rw-r--r--chromium/net/reporting/reporting_network_change_observer_unittest.cc16
-rw-r--r--chromium/net/reporting/reporting_policy.cc4
-rw-r--r--chromium/net/reporting/reporting_policy.h12
-rw-r--r--chromium/net/reporting/reporting_policy.proto4
-rw-r--r--chromium/net/reporting/reporting_report.h1
-rw-r--r--chromium/net/reporting/reporting_service.cc19
-rw-r--r--chromium/net/reporting/reporting_service.h2
-rw-r--r--chromium/net/reporting/reporting_service_unittest.cc5
-rw-r--r--chromium/net/reporting/reporting_test_util.cc35
-rw-r--r--chromium/net/reporting/reporting_test_util.h27
23 files changed, 476 insertions, 184 deletions
diff --git a/chromium/net/reporting/reporting_cache.cc b/chromium/net/reporting/reporting_cache.cc
index 0ed130bc52e..14a61c28720 100644
--- a/chromium/net/reporting/reporting_cache.cc
+++ b/chromium/net/reporting/reporting_cache.cc
@@ -100,6 +100,17 @@ class ReportingCacheImpl : public ReportingCache {
}
}
+ void GetNonpendingReports(
+ std::vector<const ReportingReport*>* reports_out) const override {
+ reports_out->clear();
+ for (const auto& it : reports_) {
+ if (!base::ContainsKey(pending_reports_, it.first) &&
+ !base::ContainsKey(doomed_reports_, it.first)) {
+ reports_out->push_back(it.second.get());
+ }
+ }
+ }
+
void SetReportsPending(
const std::vector<const ReportingReport*>& reports) override {
for (const ReportingReport* report : reports) {
@@ -236,7 +247,7 @@ class ReportingCacheImpl : public ReportingCache {
}
// If no clients were found, try successive superdomain suffixes until a
- // client with includeSubdomains is found or there are no more domain
+ // client with include-subdomains is found or there are no more domain
// components left.
std::string domain = origin.host();
while (clients_out->empty() && !domain.empty()) {
@@ -463,7 +474,7 @@ class ReportingCacheImpl : public ReportingCache {
std::map<url::Origin, std::map<GURL, std::unique_ptr<ReportingClient>>>
clients_;
- // References but does not own all clients with includeSubdomains set, keyed
+ // References but does not own all clients with include-subdomains set, keyed
// by domain name.
std::unordered_map<std::string, std::unordered_set<const ReportingClient*>>
wildcard_clients_;
diff --git a/chromium/net/reporting/reporting_cache.h b/chromium/net/reporting/reporting_cache.h
index eca3c5cd0ec..e948748c375 100644
--- a/chromium/net/reporting/reporting_cache.h
+++ b/chromium/net/reporting/reporting_cache.h
@@ -59,6 +59,14 @@ class NET_EXPORT ReportingCache {
virtual void GetReports(
std::vector<const ReportingReport*>* reports_out) const = 0;
+ // Gets all reports in the cache that aren't pending. The returned pointers
+ // are valid as long as either no calls to |RemoveReports| have happened or
+ // the reports' |pending| flag has been set to true using |SetReportsPending|.
+ //
+ // (Clears any existing data in |*reports_out|.)
+ virtual void GetNonpendingReports(
+ std::vector<const ReportingReport*>* reports_out) const = 0;
+
// Marks a set of reports as pending. |reports| must not already be marked as
// pending.
virtual void SetReportsPending(
@@ -112,9 +120,10 @@ class NET_EXPORT ReportingCache {
// have been made to |SetClient| or |RemoveEndpoint| in between.
//
// If no origin match is found, the cache will return clients from the most
- // specific superdomain which contains any clients with includeSubdomains set.
- // For example, given the origin https://foo.bar.baz.com/, the cache would
- // prioritize returning each potential match below over the ones below it:
+ // specific superdomain which contains any clients with include-subdomains
+ // set. For example, given the origin https://foo.bar.baz.com/, the cache
+ // would prioritize returning each potential match below over the ones below
+ // it:
//
// 1. https://foo.bar.baz.com/ (exact origin match)
// 2. https://foo.bar.baz.com:444/ (technically, a superdomain)
diff --git a/chromium/net/reporting/reporting_delegate.cc b/chromium/net/reporting/reporting_delegate.cc
index 42006db4b49..e25531af265 100644
--- a/chromium/net/reporting/reporting_delegate.cc
+++ b/chromium/net/reporting/reporting_delegate.cc
@@ -4,6 +4,7 @@
#include "net/reporting/reporting_delegate.h"
+#include "base/json/json_reader.h"
#include "net/base/network_delegate.h"
#include "net/url_request/url_request_context.h"
@@ -25,9 +26,16 @@ class ReportingDelegateImpl : public ReportingDelegate {
network_delegate()->CanQueueReportingReport(origin);
}
- bool CanSendReport(const url::Origin& origin) const override {
- return network_delegate() &&
- network_delegate()->CanSendReportingReport(origin);
+ void CanSendReports(std::set<url::Origin> origins,
+ base::OnceCallback<void(std::set<url::Origin>)>
+ result_callback) const override {
+ if (!network_delegate()) {
+ origins.clear();
+ std::move(result_callback).Run(std::move(origins));
+ return;
+ }
+ network_delegate()->CanSendReportingReports(std::move(origins),
+ std::move(result_callback));
}
bool CanSetClient(const url::Origin& origin,
@@ -42,6 +50,16 @@ class ReportingDelegateImpl : public ReportingDelegate {
network_delegate()->CanUseReportingClient(origin, endpoint);
}
+ void ParseJson(const std::string& unsafe_json,
+ const JsonSuccessCallback& success_callback,
+ const JsonFailureCallback& failure_callback) const override {
+ std::unique_ptr<base::Value> value = base::JSONReader::Read(unsafe_json);
+ if (value)
+ success_callback.Run(std::move(value));
+ else
+ failure_callback.Run();
+ }
+
private:
const NetworkDelegate* network_delegate() const {
return request_context_->network_delegate();
diff --git a/chromium/net/reporting/reporting_delegate.h b/chromium/net/reporting/reporting_delegate.h
index d2052f6e798..23808fafd6c 100644
--- a/chromium/net/reporting/reporting_delegate.h
+++ b/chromium/net/reporting/reporting_delegate.h
@@ -6,8 +6,11 @@
#define NET_REPORTING_REPORTING_DELEGATE_H_
#include <memory>
+#include <set>
+#include "base/callback.h"
#include "base/macros.h"
+#include "base/values.h"
#include "net/base/net_export.h"
class GURL;
@@ -27,9 +30,11 @@ class NET_EXPORT ReportingDelegate {
// Checks whether |origin| is allowed to queue reports for future delivery.
virtual bool CanQueueReport(const url::Origin& origin) const = 0;
- // Checks whether |origin| is allowed to receive reports, either in real time
- // or that were queued earlier.
- virtual bool CanSendReport(const url::Origin& origin) const = 0;
+ // Checks whether |origins| are allowed to receive reports, either in real
+ // time or that were queued earlier, removing any that aren't.
+ virtual void CanSendReports(std::set<url::Origin> origins,
+ base::OnceCallback<void(std::set<url::Origin>)>
+ result_callback) const = 0;
// Checks whether |origin| can set |endpoint| to be used for future report
// deliveries.
@@ -40,6 +45,22 @@ class NET_EXPORT ReportingDelegate {
virtual bool CanUseClient(const url::Origin& origin,
const GURL& endpoint) const = 0;
+ // TODO(crbug.com/811485): Use OnceCallback/Closure.
+ using JsonSuccessCallback =
+ base::RepeatingCallback<void(std::unique_ptr<base::Value>)>;
+ using JsonFailureCallback = base::RepeatingClosure;
+
+ // Parses JSON. How safely, and using what mechanism, is up to the embedder,
+ // but //components/data_decoder is recommended if available.
+ //
+ // Exactly one callback should be made, either to |success_callback| (with the
+ // parsed value) if parsing succeeded or to |failure_callback| if parsing
+ // failed. The callbacks may be called either synchronously or
+ // asynchronously.
+ virtual void ParseJson(const std::string& unsafe_json,
+ const JsonSuccessCallback& success_callback,
+ const JsonFailureCallback& failure_callback) const = 0;
+
static std::unique_ptr<ReportingDelegate> Create(
URLRequestContext* request_context);
};
diff --git a/chromium/net/reporting/reporting_delivery_agent.cc b/chromium/net/reporting/reporting_delivery_agent.cc
index 8786e3068c2..7a3ab2ec82c 100644
--- a/chromium/net/reporting/reporting_delivery_agent.cc
+++ b/chromium/net/reporting/reporting_delivery_agent.cc
@@ -6,6 +6,7 @@
#include <map>
#include <string>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -77,14 +78,13 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent,
private:
class Delivery {
public:
- Delivery(const GURL& endpoint,
- const std::vector<const ReportingReport*>& reports)
- : endpoint(endpoint), reports(reports) {}
+ Delivery(const GURL& endpoint, std::vector<const ReportingReport*> reports)
+ : endpoint(endpoint), reports(std::move(reports)) {}
~Delivery() = default;
const GURL endpoint;
- const std::vector<const ReportingReport*> reports;
+ std::vector<const ReportingReport*> reports;
};
using OriginGroup = std::pair<url::Origin, std::string>;
@@ -110,16 +110,34 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent,
void SendReports() {
std::vector<const ReportingReport*> reports;
- cache()->GetReports(&reports);
+ cache()->GetNonpendingReports(&reports);
+
+ // Mark all of these reports as pending, so that they're not deleted out
+ // from under us while we're checking permissions (possibly on another
+ // thread).
+ cache()->SetReportsPending(reports);
+ // First determine which origins we're allowed to upload reports about.
+ std::set<url::Origin> origins;
+ for (const ReportingReport* report : reports) {
+ origins.insert(url::Origin::Create(report->url));
+ }
+ delegate()->CanSendReports(
+ std::move(origins),
+ base::BindOnce(&ReportingDeliveryAgentImpl::OnSendPermissionsChecked,
+ weak_factory_.GetWeakPtr(), std::move(reports)));
+ }
+
+ void OnSendPermissionsChecked(std::vector<const ReportingReport*> reports,
+ std::set<url::Origin> allowed_origins) {
// Sort reports into (origin, group) buckets.
std::map<OriginGroup, std::vector<const ReportingReport*>>
origin_group_reports;
for (const ReportingReport* report : reports) {
url::Origin origin = url::Origin::Create(report->url);
- if (!delegate()->CanSendReport(origin))
+ if (allowed_origins.find(origin) == allowed_origins.end())
continue;
- OriginGroup origin_group(url::Origin::Create(report->url), report->group);
+ OriginGroup origin_group(origin, report->group);
origin_group_reports[origin_group].push_back(report);
}
@@ -147,23 +165,34 @@ class ReportingDeliveryAgentImpl : public ReportingDeliveryAgent,
pending_origin_groups_.insert(origin_group);
}
+ // Keep track of which of these reports we don't queue for delivery; we'll
+ // need to mark them as not-pending.
+ std::unordered_set<const ReportingReport*> undelivered_reports(
+ reports.begin(), reports.end());
+
// Start a delivery to each endpoint.
for (auto& it : endpoint_reports) {
const GURL& endpoint = it.first;
const std::vector<const ReportingReport*>& reports = it.second;
endpoint_manager()->SetEndpointPending(endpoint);
- cache()->SetReportsPending(reports);
std::string json;
SerializeReports(reports, tick_clock()->NowTicks(), &json);
+ for (const ReportingReport* report : reports)
+ undelivered_reports.erase(report);
+
uploader()->StartUpload(
endpoint, json,
- base::BindOnce(&ReportingDeliveryAgentImpl::OnUploadComplete,
- weak_factory_.GetWeakPtr(),
- std::make_unique<Delivery>(endpoint, reports)));
+ base::BindOnce(
+ &ReportingDeliveryAgentImpl::OnUploadComplete,
+ weak_factory_.GetWeakPtr(),
+ std::make_unique<Delivery>(endpoint, std::move(reports))));
}
+
+ cache()->ClearReportsPending(
+ {undelivered_reports.begin(), undelivered_reports.end()});
}
void OnUploadComplete(const std::unique_ptr<Delivery>& delivery,
diff --git a/chromium/net/reporting/reporting_delivery_agent_unittest.cc b/chromium/net/reporting/reporting_delivery_agent_unittest.cc
index c4e233a9ad2..c5b1a418c14 100644
--- a/chromium/net/reporting/reporting_delivery_agent_unittest.cc
+++ b/chromium/net/reporting/reporting_delivery_agent_unittest.cc
@@ -126,6 +126,35 @@ TEST_F(ReportingDeliveryAgentTest, FailedUpload) {
EXPECT_TRUE(pending_uploads().empty());
}
+TEST_F(ReportingDeliveryAgentTest, DisallowedUpload) {
+ // This mimics the check that is controlled by the BACKGROUND_SYNC permission
+ // in a real browser profile.
+ context()->test_delegate()->set_disallow_report_uploads(true);
+
+ static const int kAgeMillis = 12345;
+
+ base::DictionaryValue body;
+ body.SetString("key", "value");
+
+ SetClient(kOrigin_, kEndpoint_, kGroup_);
+ cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(),
+ tick_clock()->NowTicks(), 0);
+
+ tick_clock()->Advance(base::TimeDelta::FromMilliseconds(kAgeMillis));
+
+ EXPECT_TRUE(delivery_timer()->IsRunning());
+ delivery_timer()->Fire();
+
+ // We should not try to upload the report, since we weren't given permission
+ // for this origin.
+ EXPECT_TRUE(pending_uploads().empty());
+
+ // Disallowed reports should NOT have been removed from the cache.
+ std::vector<const ReportingReport*> reports;
+ cache()->GetReports(&reports);
+ EXPECT_EQ(1u, reports.size());
+}
+
TEST_F(ReportingDeliveryAgentTest, RemoveEndpointUpload) {
static const url::Origin kDifferentOrigin =
url::Origin::Create(GURL("https://origin2/"));
@@ -195,6 +224,47 @@ TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) {
EXPECT_FALSE(cache()->IsReportDoomedForTesting(report));
}
+TEST_F(ReportingDeliveryAgentTest, ConcurrentRemoveDuringPermissionsCheck) {
+ // Pause the permissions check, so that we can try to remove some reports
+ // while we're in the middle of verifying that we can upload them. (This is
+ // similar to the previous test, but removes the reports during a different
+ // part of the upload process.)
+ context()->test_delegate()->set_pause_permissions_check(true);
+
+ SetClient(kOrigin_, kEndpoint_, kGroup_);
+ cache()->AddReport(kUrl_, kGroup_, kType_,
+ std::make_unique<base::DictionaryValue>(),
+ tick_clock()->NowTicks(), 0);
+
+ EXPECT_TRUE(delivery_timer()->IsRunning());
+ delivery_timer()->Fire();
+ ASSERT_TRUE(context()->test_delegate()->PermissionsCheckPaused());
+
+ // Remove the report while the upload is running.
+ std::vector<const ReportingReport*> reports;
+ cache()->GetReports(&reports);
+ EXPECT_EQ(1u, reports.size());
+
+ const ReportingReport* report = reports[0];
+ EXPECT_FALSE(cache()->IsReportDoomedForTesting(report));
+
+ // Report should appear removed, even though the cache has doomed it.
+ cache()->RemoveReports(reports, ReportingReport::Outcome::UNKNOWN);
+ cache()->GetReports(&reports);
+ EXPECT_TRUE(reports.empty());
+ EXPECT_TRUE(cache()->IsReportDoomedForTesting(report));
+
+ // Completing upload shouldn't crash, and report should still be gone.
+ context()->test_delegate()->ResumePermissionsCheck();
+ ASSERT_EQ(1u, pending_uploads().size());
+ pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
+ cache()->GetReports(&reports);
+ EXPECT_TRUE(reports.empty());
+ // This is slightly sketchy since |report| has been freed, but it nonetheless
+ // should not be in the set of doomed reports.
+ EXPECT_FALSE(cache()->IsReportDoomedForTesting(report));
+}
+
// Test that the agent will combine reports destined for the same endpoint, even
// if the reports are from different origins.
TEST_F(ReportingDeliveryAgentTest,
diff --git a/chromium/net/reporting/reporting_feature.cc b/chromium/net/reporting/reporting_feature.cc
deleted file mode 100644
index 9f4e28eac70..00000000000
--- a/chromium/net/reporting/reporting_feature.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2017 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 "net/reporting/reporting_feature.h"
-
-namespace features {
-
-const base::Feature kReporting{"Reporting", base::FEATURE_DISABLED_BY_DEFAULT};
-
-} // namespace features
diff --git a/chromium/net/reporting/reporting_feature.h b/chromium/net/reporting/reporting_feature.h
deleted file mode 100644
index 4bd3d39e81e..00000000000
--- a/chromium/net/reporting/reporting_feature.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef NET_REPORTING_REPORTING_FEATURE_H_
-#define NET_REPORTING_REPORTING_FEATURE_H_
-
-#include "base/feature_list.h"
-#include "net/base/net_export.h"
-
-namespace features {
-
-extern const base::Feature NET_EXPORT kReporting;
-
-} // namespace features
-
-#endif // NET_REPORTING_REPORTING_FEATURE_H_
diff --git a/chromium/net/reporting/reporting_header_parser.cc b/chromium/net/reporting/reporting_header_parser.cc
index 5512a5b7fe5..e482a55e41a 100644
--- a/chromium/net/reporting/reporting_header_parser.cc
+++ b/chromium/net/reporting/reporting_header_parser.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
@@ -36,16 +37,34 @@ void RecordHeaderOutcome(HeaderOutcome outcome) {
HeaderOutcome::MAX);
}
+enum class HeaderEndpointGroupOutcome {
+ DISCARDED_NOT_DICTIONARY = 0,
+ DISCARDED_GROUP_NOT_STRING = 1,
+ DISCARDED_TTL_MISSING = 2,
+ DISCARDED_TTL_NOT_INTEGER = 3,
+ DISCARDED_TTL_NEGATIVE = 4,
+ DISCARDED_ENDPOINTS_MISSING = 5,
+ DISCARDED_ENDPOINTS_NOT_LIST = 6,
+ PARSED = 7,
+
+ MAX
+};
+
+void RecordHeaderEndpointGroupOutcome(HeaderEndpointGroupOutcome outcome) {
+ UMA_HISTOGRAM_ENUMERATION("Reporting.HeaderEndpointGroupOutcome", outcome,
+ HeaderEndpointGroupOutcome::MAX);
+}
+
enum class HeaderEndpointOutcome {
DISCARDED_NOT_DICTIONARY = 0,
- DISCARDED_ENDPOINT_MISSING = 1,
- DISCARDED_ENDPOINT_NOT_STRING = 2,
- DISCARDED_ENDPOINT_INVALID = 3,
- DISCARDED_ENDPOINT_INSECURE = 4,
- DISCARDED_TTL_MISSING = 5,
- DISCARDED_TTL_NOT_INTEGER = 6,
- DISCARDED_TTL_NEGATIVE = 7,
- DISCARDED_GROUP_NOT_STRING = 8,
+ DISCARDED_ENDPOINT_MISSING = 1, // obsolete
+ DISCARDED_ENDPOINT_NOT_STRING = 2, // obsolete
+ DISCARDED_ENDPOINT_INVALID = 3, // obsolete
+ DISCARDED_ENDPOINT_INSECURE = 4, // obsolete
+ DISCARDED_TTL_MISSING = 5, // obsolete
+ DISCARDED_TTL_NOT_INTEGER = 6, // obsolete
+ DISCARDED_TTL_NEGATIVE = 7, // obsolete
+ DISCARDED_GROUP_NOT_STRING = 8, // obsolete
REMOVED = 9,
SET_REJECTED_BY_DELEGATE = 10,
SET = 11,
@@ -54,6 +73,11 @@ enum class HeaderEndpointOutcome {
DISCARDED_WEIGHT_NOT_INTEGER = 13,
DISCARDED_WEIGHT_NOT_POSITIVE = 14,
+ DISCARDED_URL_MISSING = 15,
+ DISCARDED_URL_NOT_STRING = 16,
+ DISCARDED_URL_INVALID = 17,
+ DISCARDED_URL_INSECURE = 18,
+
MAX
};
@@ -69,7 +93,8 @@ void RecordHeaderEndpointOutcome(HeaderEndpointOutcome outcome) {
}
const char kUrlKey[] = "url";
-const char kIncludeSubdomainsKey[] = "includeSubdomains";
+const char kIncludeSubdomainsKey[] = "include-subdomains";
+const char kEndpointsKey[] = "endpoints";
const char kGroupKey[] = "group";
const char kGroupDefaultValue[] = "default";
const char kMaxAgeKey[] = "max-age";
@@ -86,6 +111,9 @@ const char kWeightKey[] = "weight";
HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate,
ReportingCache* cache,
base::TimeTicks now,
+ const std::string& group,
+ int ttl_sec,
+ ReportingClient::Subdomains subdomains,
const url::Origin& origin,
const base::Value& value,
GURL* endpoint_url_out) {
@@ -98,35 +126,15 @@ HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate,
std::string endpoint_url_string;
if (!dict->HasKey(kUrlKey))
- return HeaderEndpointOutcome::DISCARDED_ENDPOINT_MISSING;
+ return HeaderEndpointOutcome::DISCARDED_URL_MISSING;
if (!dict->GetString(kUrlKey, &endpoint_url_string))
- return HeaderEndpointOutcome::DISCARDED_ENDPOINT_NOT_STRING;
+ return HeaderEndpointOutcome::DISCARDED_URL_NOT_STRING;
GURL endpoint_url(endpoint_url_string);
if (!endpoint_url.is_valid())
- return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INVALID;
+ return HeaderEndpointOutcome::DISCARDED_URL_INVALID;
if (!endpoint_url.SchemeIsCryptographic())
- return HeaderEndpointOutcome::DISCARDED_ENDPOINT_INSECURE;
-
- int ttl_sec = -1;
- if (!dict->HasKey(kMaxAgeKey))
- return HeaderEndpointOutcome::DISCARDED_TTL_MISSING;
- if (!dict->GetInteger(kMaxAgeKey, &ttl_sec))
- return HeaderEndpointOutcome::DISCARDED_TTL_NOT_INTEGER;
- if (ttl_sec < 0)
- return HeaderEndpointOutcome::DISCARDED_TTL_NEGATIVE;
-
- std::string group = kGroupDefaultValue;
- if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group))
- return HeaderEndpointOutcome::DISCARDED_GROUP_NOT_STRING;
-
- ReportingClient::Subdomains subdomains = ReportingClient::Subdomains::EXCLUDE;
- bool subdomains_bool = false;
- if (dict->HasKey(kIncludeSubdomainsKey) &&
- dict->GetBoolean(kIncludeSubdomainsKey, &subdomains_bool) &&
- subdomains_bool == true) {
- subdomains = ReportingClient::Subdomains::INCLUDE;
- }
+ return HeaderEndpointOutcome::DISCARDED_URL_INSECURE;
int priority = ReportingClient::kDefaultPriority;
if (dict->HasKey(kPriorityKey) && !dict->GetInteger(kPriorityKey, &priority))
@@ -154,6 +162,65 @@ HeaderEndpointOutcome ProcessEndpoint(ReportingDelegate* delegate,
return HeaderEndpointOutcome::SET;
}
+// Processes a single endpoint group tuple received in a Report-To header.
+//
+// |origin| is the origin that sent the Report-To header.
+//
+// |value| is the parsed JSON value of the endpoint group tuple.
+HeaderEndpointGroupOutcome ProcessEndpointGroup(ReportingDelegate* delegate,
+ ReportingCache* cache,
+ std::set<GURL>* new_endpoints,
+ base::TimeTicks now,
+ const url::Origin& origin,
+ const base::Value& value) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!value.GetAsDictionary(&dict))
+ return HeaderEndpointGroupOutcome::DISCARDED_NOT_DICTIONARY;
+ DCHECK(dict);
+
+ std::string group = kGroupDefaultValue;
+ if (dict->HasKey(kGroupKey) && !dict->GetString(kGroupKey, &group))
+ return HeaderEndpointGroupOutcome::DISCARDED_GROUP_NOT_STRING;
+
+ int ttl_sec = -1;
+ if (!dict->HasKey(kMaxAgeKey))
+ return HeaderEndpointGroupOutcome::DISCARDED_TTL_MISSING;
+ if (!dict->GetInteger(kMaxAgeKey, &ttl_sec))
+ return HeaderEndpointGroupOutcome::DISCARDED_TTL_NOT_INTEGER;
+ if (ttl_sec < 0)
+ return HeaderEndpointGroupOutcome::DISCARDED_TTL_NEGATIVE;
+
+ ReportingClient::Subdomains subdomains = ReportingClient::Subdomains::EXCLUDE;
+ bool subdomains_bool = false;
+ if (dict->HasKey(kIncludeSubdomainsKey) &&
+ dict->GetBoolean(kIncludeSubdomainsKey, &subdomains_bool) &&
+ subdomains_bool == true) {
+ subdomains = ReportingClient::Subdomains::INCLUDE;
+ }
+
+ const base::ListValue* endpoint_list = nullptr;
+ if (!dict->HasKey(kEndpointsKey))
+ return HeaderEndpointGroupOutcome::DISCARDED_ENDPOINTS_MISSING;
+ if (!dict->GetList(kEndpointsKey, &endpoint_list))
+ return HeaderEndpointGroupOutcome::DISCARDED_ENDPOINTS_NOT_LIST;
+
+ for (size_t i = 0; i < endpoint_list->GetSize(); i++) {
+ const base::Value* endpoint = nullptr;
+ bool got_endpoint = endpoint_list->Get(i, &endpoint);
+ DCHECK(got_endpoint);
+ GURL endpoint_url;
+
+ HeaderEndpointOutcome outcome =
+ ProcessEndpoint(delegate, cache, now, group, ttl_sec, subdomains,
+ origin, *endpoint, &endpoint_url);
+ if (EndpointParsedSuccessfully(outcome))
+ new_endpoints->insert(endpoint_url);
+ RecordHeaderEndpointOutcome(outcome);
+ }
+
+ return HeaderEndpointGroupOutcome::PARSED;
+}
+
} // namespace
// static
@@ -172,20 +239,18 @@ void ReportingHeaderParser::RecordHeaderDiscardedForCertStatusError() {
}
// static
+void ReportingHeaderParser::RecordHeaderDiscardedForInvalidJson() {
+ RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_JSON);
+}
+
+// static
void ReportingHeaderParser::ParseHeader(ReportingContext* context,
const GURL& url,
- const std::string& json_value) {
+ std::unique_ptr<base::Value> value) {
DCHECK(url.SchemeIsCryptographic());
- std::unique_ptr<base::Value> value =
- base::JSONReader::Read("[" + json_value + "]");
- if (!value) {
- RecordHeaderOutcome(HeaderOutcome::DISCARDED_INVALID_JSON);
- return;
- }
-
- const base::ListValue* endpoint_list = nullptr;
- bool is_list = value->GetAsList(&endpoint_list);
+ const base::ListValue* group_list = nullptr;
+ bool is_list = value->GetAsList(&group_list);
DCHECK(is_list);
ReportingDelegate* delegate = context->delegate();
@@ -199,16 +264,13 @@ void ReportingHeaderParser::ParseHeader(ReportingContext* context,
std::set<GURL> new_endpoints;
base::TimeTicks now = context->tick_clock()->NowTicks();
- for (size_t i = 0; i < endpoint_list->GetSize(); i++) {
- const base::Value* endpoint = nullptr;
- bool got_endpoint = endpoint_list->Get(i, &endpoint);
- DCHECK(got_endpoint);
- GURL endpoint_url;
- HeaderEndpointOutcome outcome =
- ProcessEndpoint(delegate, cache, now, origin, *endpoint, &endpoint_url);
- if (EndpointParsedSuccessfully(outcome))
- new_endpoints.insert(endpoint_url);
- RecordHeaderEndpointOutcome(outcome);
+ for (size_t i = 0; i < group_list->GetSize(); i++) {
+ const base::Value* group = nullptr;
+ bool got_group = group_list->Get(i, &group);
+ DCHECK(got_group);
+ HeaderEndpointGroupOutcome outcome = ProcessEndpointGroup(
+ delegate, cache, &new_endpoints, now, origin, *group);
+ RecordHeaderEndpointGroupOutcome(outcome);
}
// Remove any endpoints that weren't specified in the current header(s).
diff --git a/chromium/net/reporting/reporting_header_parser.h b/chromium/net/reporting/reporting_header_parser.h
index c94f0537227..94a29beee7c 100644
--- a/chromium/net/reporting/reporting_header_parser.h
+++ b/chromium/net/reporting/reporting_header_parser.h
@@ -5,13 +5,17 @@
#ifndef NET_REPORTING_REPORTING_HEADER_PARSER_H_
#define NET_REPORTING_REPORTING_HEADER_PARSER_H_
-#include <string>
+#include <memory>
#include "base/macros.h"
#include "net/base/net_export.h"
class GURL;
+namespace base {
+class Value;
+} // namespace base
+
namespace net {
class ReportingContext;
@@ -21,10 +25,11 @@ class NET_EXPORT ReportingHeaderParser {
static void RecordHeaderDiscardedForNoReportingService();
static void RecordHeaderDiscardedForInvalidSSLInfo();
static void RecordHeaderDiscardedForCertStatusError();
+ static void RecordHeaderDiscardedForInvalidJson();
static void ParseHeader(ReportingContext* context,
const GURL& url,
- const std::string& json_value);
+ std::unique_ptr<base::Value> value);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ReportingHeaderParser);
diff --git a/chromium/net/reporting/reporting_header_parser_fuzzer.cc b/chromium/net/reporting/reporting_header_parser_fuzzer.cc
index 470d496a633..f050eae1440 100644
--- a/chromium/net/reporting/reporting_header_parser_fuzzer.cc
+++ b/chromium/net/reporting/reporting_header_parser_fuzzer.cc
@@ -2,9 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
+#include <utility>
+
+#include "base/json/json_reader.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
+#include "base/values.h"
#include "net/reporting/reporting_cache.h"
#include "net/reporting/reporting_client.h"
#include "net/reporting/reporting_header_parser.h"
@@ -24,12 +29,20 @@ const GURL kUrl_ = GURL("https://origin/path");
namespace net_reporting_header_parser_fuzzer {
-void FuzzReportingHeaderParser(const std::string& data,
- const net::ReportingPolicy& policy) {
+void FuzzReportingHeaderParser(const std::string& data_json,
+ const net::ReportingPolicy& policy) {
net::TestReportingContext context(base::DefaultClock::GetInstance(),
base::DefaultTickClock::GetInstance(),
policy);
- net::ReportingHeaderParser::ParseHeader(&context, kUrl_, data.c_str());
+ // Emulate what ReportingService::OnHeader does before calling
+ // ReportingHeaderParser::ParseHeader.
+ std::unique_ptr<base::Value> data_value =
+ base::JSONReader::Read("[" + data_json + "]");
+ if (!data_value)
+ return;
+
+ net::ReportingHeaderParser::ParseHeader(&context, kUrl_,
+ std::move(data_value));
std::vector<const net::ReportingClient*> clients;
context.cache()->GetClients(&clients);
if (clients.empty()) {
@@ -55,10 +68,10 @@ void InitializeReportingPolicy(
policy.max_report_age =
base::TimeDelta::FromMicroseconds(policy_data.max_report_age_us());
policy.max_report_attempts = policy_data.max_report_attempts();
- policy.clear_reports_on_network_changes =
- policy_data.clear_reports_on_network_changes();
- policy.clear_clients_on_network_changes =
- policy_data.clear_clients_on_network_changes();
+ policy.persist_reports_across_network_changes =
+ policy_data.persist_reports_across_network_changes();
+ policy.persist_clients_across_network_changes =
+ policy_data.persist_clients_across_network_changes();
}
DEFINE_BINARY_PROTO_FUZZER(
diff --git a/chromium/net/reporting/reporting_header_parser_unittest.cc b/chromium/net/reporting/reporting_header_parser_unittest.cc
index 151675e6d12..125959dcf82 100644
--- a/chromium/net/reporting/reporting_header_parser_unittest.cc
+++ b/chromium/net/reporting/reporting_header_parser_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
+#include "base/json/json_reader.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "base/values.h"
@@ -22,6 +23,13 @@ namespace {
class ReportingHeaderParserTest : public ReportingTestBase {
protected:
+ void ParseHeader(const GURL& url, const std::string& json) {
+ std::unique_ptr<base::Value> value =
+ base::JSONReader::Read("[" + json + "]");
+ if (value)
+ ReportingHeaderParser::ParseHeader(context(), url, std::move(value));
+ }
+
const GURL kUrl_ = GURL("https://origin/path");
const url::Origin kOrigin_ = url::Origin::Create(GURL("https://origin/"));
const GURL kEndpoint_ = GURL("https://endpoint/");
@@ -29,44 +37,53 @@ class ReportingHeaderParserTest : public ReportingTestBase {
const std::string kType_ = "type";
};
+// TODO(juliatuttle): Ideally these tests should be expecting that JSON parsing
+// (and therefore header parsing) may happen asynchronously, but the entire
+// pipeline is also tested by NetworkErrorLoggingEndToEndTest.
+
TEST_F(ReportingHeaderParserTest, Invalid) {
static const struct {
const char* header_value;
const char* description;
} kInvalidHeaderTestCases[] = {
- {"{\"max-age\":1}", "missing url"},
- {"{\"url\":0,\"max-age\":1}", "non-string url"},
- {"{\"url\":\"http://insecure/\",\"max-age\":1}", "insecure url"},
+ {"{\"max-age\":1, \"endpoints\": [{}]}", "missing url"},
+ {"{\"max-age\":1, \"endpoints\": [{\"url\":0}]}", "non-string url"},
+ {"{\"max-age\":1, \"endpoints\": [{\"url\":\"http://insecure/\"}]}",
+ "insecure url"},
- {"{\"url\":\"https://endpoint/\"}", "missing max-age"},
- {"{\"url\":\"https://endpoint/\",\"max-age\":\"\"}",
+ {"{\"endpoints\": [{\"url\":\"https://endpoint/\"}]}", "missing max-age"},
+ {"{\"max-age\":\"\", \"endpoints\": [{\"url\":\"https://endpoint/\"}]}",
"non-integer max-age"},
- {"{\"url\":\"https://endpoint/\",\"max-age\":-1}", "negative max-age"},
-
- {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"group\":0}",
+ {"{\"max-age\":-1, \"endpoints\": [{\"url\":\"https://endpoint/\"}]}",
+ "negative max-age"},
+ {"{\"max-age\":1, \"group\":0, "
+ "\"endpoints\": [{\"url\":\"https://endpoint/\"}]}",
"non-string group"},
- // Note that a non-boolean includeSubdomains field is *not* invalid, per
+ // Note that a non-boolean include-subdomains field is *not* invalid, per
// the spec.
- {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"priority\":\"\"}",
+ {"{\"max-age\":1, "
+ "\"endpoints\": [{\"url\":\"https://endpoint/\",\"priority\":\"\"}]}",
"non-integer priority"},
- {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"weight\":\"\"}",
+ {"{\"max-age\":1, "
+ "\"endpoints\": [{\"url\":\"https://endpoint/\",\"weight\":\"\"}]}",
"non-integer weight"},
- {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"weight\":-1}",
+ {"{\"max-age\":1, "
+ "\"endpoints\": [{\"url\":\"https://endpoint/\",\"weight\":-1}]}",
"negative weight"},
- {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"weight\":0}",
+ {"{\"max-age\":1, "
+ "\"endpoints\": [{\"url\":\"https://endpoint/\",\"weight\":0}]}",
"zero weight"},
- {"[{\"url\":\"https://a/\",\"max-age\":1},"
- "{\"url\":\"https://b/\",\"max-age\":1}]",
+ {"[{\"max-age\":1, \"endpoints\": [{\"url\":\"https://a/\"}]},"
+ "{\"max-age\":1, \"endpoints\": [{\"url\":\"https://b/\"}]}]",
"wrapped in list"}};
for (size_t i = 0; i < arraysize(kInvalidHeaderTestCases); ++i) {
auto& test_case = kInvalidHeaderTestCases[i];
- ReportingHeaderParser::ParseHeader(context(), kUrl_,
- test_case.header_value);
+ ParseHeader(kUrl_, test_case.header_value);
std::vector<const ReportingClient*> clients;
cache()->GetClients(&clients);
@@ -77,9 +94,8 @@ TEST_F(ReportingHeaderParserTest, Invalid) {
}
TEST_F(ReportingHeaderParserTest, Valid) {
- ReportingHeaderParser::ParseHeader(
- context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() + "\",\"max-age\":86400}");
+ ParseHeader(kUrl_, "{\"endpoints\": [{\"url\":\"" + kEndpoint_.spec() +
+ "\"}],\"max-age\":86400}");
const ReportingClient* client =
FindClientInCache(cache(), kOrigin_, kEndpoint_);
@@ -98,18 +114,16 @@ TEST_F(ReportingHeaderParserTest, ZeroMaxAge) {
tick_clock()->NowTicks() + base::TimeDelta::FromDays(1),
ReportingClient::kDefaultPriority, ReportingClient::kDefaultWeight);
- ReportingHeaderParser::ParseHeader(
- context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() + "\",\"max-age\":0}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
+ "\"}],\"max-age\":0}");
EXPECT_EQ(nullptr, FindClientInCache(cache(), kOrigin_, kEndpoint_));
}
TEST_F(ReportingHeaderParserTest, Subdomains) {
- ReportingHeaderParser::ParseHeader(context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() +
- "\",\"max-age\":86400,"
- "\"includeSubdomains\":true}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
+ "\"}],\"max-age\":86400,"
+ "\"include-subdomains\":true}");
const ReportingClient* client =
FindClientInCache(cache(), kOrigin_, kEndpoint_);
@@ -118,10 +132,8 @@ TEST_F(ReportingHeaderParserTest, Subdomains) {
}
TEST_F(ReportingHeaderParserTest, PriorityPositive) {
- ReportingHeaderParser::ParseHeader(context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() +
- "\",\"max-age\":86400,"
- "\"priority\":2}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
+ "\",\"priority\":2}],\"max-age\":86400}");
const ReportingClient* client =
FindClientInCache(cache(), kOrigin_, kEndpoint_);
@@ -130,10 +142,8 @@ TEST_F(ReportingHeaderParserTest, PriorityPositive) {
}
TEST_F(ReportingHeaderParserTest, PriorityNegative) {
- ReportingHeaderParser::ParseHeader(context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() +
- "\",\"max-age\":86400,"
- "\"priority\":-2}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
+ "\",\"priority\":-2}],\"max-age\":86400}");
const ReportingClient* client =
FindClientInCache(cache(), kOrigin_, kEndpoint_);
@@ -142,10 +152,8 @@ TEST_F(ReportingHeaderParserTest, PriorityNegative) {
}
TEST_F(ReportingHeaderParserTest, Weight) {
- ReportingHeaderParser::ParseHeader(context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() +
- "\",\"max-age\":86400,"
- "\"weight\":3}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
+ "\",\"weight\":3}],\"max-age\":86400}");
const ReportingClient* client =
FindClientInCache(cache(), kOrigin_, kEndpoint_);
@@ -156,15 +164,14 @@ TEST_F(ReportingHeaderParserTest, Weight) {
TEST_F(ReportingHeaderParserTest, RemoveOld) {
static const GURL kDifferentEndpoint_ = GURL("https://endpoint2/");
- ReportingHeaderParser::ParseHeader(
- context(), kUrl_,
- "{\"url\":\"" + kEndpoint_.spec() + "\",\"max-age\":86400}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
+ "\"}],\"max-age\":86400}");
EXPECT_TRUE(FindClientInCache(cache(), kOrigin_, kEndpoint_));
- ReportingHeaderParser::ParseHeader(
- context(), kUrl_,
- "{\"url\":\"" + kDifferentEndpoint_.spec() + "\",\"max-age\":86400}");
+ ParseHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" +
+ kDifferentEndpoint_.spec() +
+ "\"}],\"max-age\":86400}");
EXPECT_FALSE(FindClientInCache(cache(), kOrigin_, kEndpoint_));
EXPECT_TRUE(FindClientInCache(cache(), kOrigin_, kDifferentEndpoint_));
diff --git a/chromium/net/reporting/reporting_network_change_observer.cc b/chromium/net/reporting/reporting_network_change_observer.cc
index 20e33a303eb..c7acb8843fe 100644
--- a/chromium/net/reporting/reporting_network_change_observer.cc
+++ b/chromium/net/reporting/reporting_network_change_observer.cc
@@ -38,11 +38,11 @@ class ReportingNetworkChangeObserverImpl
if (type != NetworkChangeNotifier::ConnectionType::CONNECTION_NONE)
return;
- if (context_->policy().clear_reports_on_network_changes)
+ if (!context_->policy().persist_reports_across_network_changes)
context_->cache()->RemoveAllReports(
ReportingReport::Outcome::ERASED_NETWORK_CHANGED);
- if (context_->policy().clear_clients_on_network_changes)
+ if (!context_->policy().persist_clients_across_network_changes)
context_->cache()->RemoveAllClients();
}
diff --git a/chromium/net/reporting/reporting_network_change_observer_unittest.cc b/chromium/net/reporting/reporting_network_change_observer_unittest.cc
index ce114d1ab3b..ae35fbda87e 100644
--- a/chromium/net/reporting/reporting_network_change_observer_unittest.cc
+++ b/chromium/net/reporting/reporting_network_change_observer_unittest.cc
@@ -60,8 +60,8 @@ class ReportingNetworkChangeObserverTest : public ReportingTestBase {
TEST_F(ReportingNetworkChangeObserverTest, ClearNothing) {
ReportingPolicy new_policy = policy();
- new_policy.clear_reports_on_network_changes = false;
- new_policy.clear_clients_on_network_changes = false;
+ new_policy.persist_reports_across_network_changes = true;
+ new_policy.persist_clients_across_network_changes = true;
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
@@ -79,8 +79,8 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearNothing) {
TEST_F(ReportingNetworkChangeObserverTest, ClearReports) {
ReportingPolicy new_policy = policy();
- new_policy.clear_reports_on_network_changes = true;
- new_policy.clear_clients_on_network_changes = false;
+ new_policy.persist_reports_across_network_changes = false;
+ new_policy.persist_clients_across_network_changes = true;
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
@@ -98,8 +98,8 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearReports) {
TEST_F(ReportingNetworkChangeObserverTest, ClearClients) {
ReportingPolicy new_policy = policy();
- new_policy.clear_reports_on_network_changes = false;
- new_policy.clear_clients_on_network_changes = true;
+ new_policy.persist_reports_across_network_changes = true;
+ new_policy.persist_clients_across_network_changes = false;
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
@@ -117,8 +117,8 @@ TEST_F(ReportingNetworkChangeObserverTest, ClearClients) {
TEST_F(ReportingNetworkChangeObserverTest, ClearReportsAndClients) {
ReportingPolicy new_policy = policy();
- new_policy.clear_reports_on_network_changes = true;
- new_policy.clear_clients_on_network_changes = true;
+ new_policy.persist_reports_across_network_changes = false;
+ new_policy.persist_clients_across_network_changes = false;
UsePolicy(new_policy);
cache()->AddReport(kUrl_, kGroup_, kType_,
diff --git a/chromium/net/reporting/reporting_policy.cc b/chromium/net/reporting/reporting_policy.cc
index 007eb89bd9a..1c4d163e7b2 100644
--- a/chromium/net/reporting/reporting_policy.cc
+++ b/chromium/net/reporting/reporting_policy.cc
@@ -18,8 +18,8 @@ ReportingPolicy::ReportingPolicy()
garbage_collection_interval(base::TimeDelta::FromMinutes(5)),
max_report_age(base::TimeDelta::FromMinutes(15)),
max_report_attempts(5),
- clear_reports_on_network_changes(true),
- clear_clients_on_network_changes(false) {
+ persist_reports_across_network_changes(false),
+ persist_clients_across_network_changes(true) {
endpoint_backoff_policy.num_errors_to_ignore = 0;
endpoint_backoff_policy.initial_delay_ms = 60 * 1000; // 1 minute
endpoint_backoff_policy.multiply_factor = 2.0;
diff --git a/chromium/net/reporting/reporting_policy.h b/chromium/net/reporting/reporting_policy.h
index 772bff51f03..86d88586c6a 100644
--- a/chromium/net/reporting/reporting_policy.h
+++ b/chromium/net/reporting/reporting_policy.h
@@ -51,13 +51,13 @@ struct NET_EXPORT ReportingPolicy {
// discarded as failed.
int max_report_attempts;
- // Whether to clear reports when the network changes to avoid leaking browsing
- // data between networks.
- bool clear_reports_on_network_changes;
+ // Whether to persist (versus clear) reports when the network changes to avoid
+ // leaking browsing data between networks.
+ bool persist_reports_across_network_changes;
- // Whether to clear clients when the network changes to avoid leaking browsing
- // data between networks.
- bool clear_clients_on_network_changes;
+ // Whether to persist (versus clear) clients when the network changes to avoid
+ // leaking browsing data between networks.
+ bool persist_clients_across_network_changes;
};
} // namespace net
diff --git a/chromium/net/reporting/reporting_policy.proto b/chromium/net/reporting/reporting_policy.proto
index c908b8635de..c7b9cb07db7 100644
--- a/chromium/net/reporting/reporting_policy.proto
+++ b/chromium/net/reporting/reporting_policy.proto
@@ -21,8 +21,8 @@ message ReportingPolicy {
required uint64 garbage_collection_interval_us = 7;
required uint64 max_report_age_us = 8;
required int32 max_report_attempts = 9;
- required bool clear_reports_on_network_changes = 10;
- required bool clear_clients_on_network_changes = 11;
+ required bool persist_reports_across_network_changes = 10;
+ required bool persist_clients_across_network_changes = 11;
}
message ReportingHeaderParserFuzzInput {
diff --git a/chromium/net/reporting/reporting_report.h b/chromium/net/reporting/reporting_report.h
index e7fba5d5950..1621ab0a49d 100644
--- a/chromium/net/reporting/reporting_report.h
+++ b/chromium/net/reporting/reporting_report.h
@@ -33,6 +33,7 @@ struct NET_EXPORT ReportingReport {
ERASED_BROWSING_DATA_REMOVED = 7,
ERASED_REPORTING_SHUT_DOWN = 8,
DELIVERED = 9,
+ ERASED_NO_BACKGROUND_SYNC_PERMISSION = 10,
MAX
};
diff --git a/chromium/net/reporting/reporting_service.cc b/chromium/net/reporting/reporting_service.cc
index 59976e23224..5137082775d 100644
--- a/chromium/net/reporting/reporting_service.cc
+++ b/chromium/net/reporting/reporting_service.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/values.h"
@@ -26,7 +27,7 @@ namespace {
class ReportingServiceImpl : public ReportingService {
public:
ReportingServiceImpl(std::unique_ptr<ReportingContext> context)
- : context_(std::move(context)) {}
+ : context_(std::move(context)), weak_factory_(this) {}
// ReportingService implementation:
@@ -48,7 +49,12 @@ class ReportingServiceImpl : public ReportingService {
void ProcessHeader(const GURL& url,
const std::string& header_value) override {
- ReportingHeaderParser::ParseHeader(context_.get(), url, header_value);
+ context_->delegate()->ParseJson(
+ "[" + header_value + "]",
+ base::BindRepeating(&ReportingServiceImpl::ProcessHeaderValue,
+ weak_factory_.GetWeakPtr(), url),
+ base::BindRepeating(
+ &ReportingHeaderParser::RecordHeaderDiscardedForInvalidJson));
}
void RemoveBrowsingData(int data_type_mask,
@@ -62,8 +68,17 @@ class ReportingServiceImpl : public ReportingService {
return context_->uploader()->RequestIsUpload(request);
}
+ const ReportingPolicy& GetPolicy() const override {
+ return context_->policy();
+ }
+
private:
+ void ProcessHeaderValue(const GURL& url, std::unique_ptr<base::Value> value) {
+ ReportingHeaderParser::ParseHeader(context_.get(), url, std::move(value));
+ }
+
std::unique_ptr<ReportingContext> context_;
+ base::WeakPtrFactory<ReportingServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ReportingServiceImpl);
};
diff --git a/chromium/net/reporting/reporting_service.h b/chromium/net/reporting/reporting_service.h
index aa7dc40e369..37958702e00 100644
--- a/chromium/net/reporting/reporting_service.h
+++ b/chromium/net/reporting/reporting_service.h
@@ -70,6 +70,8 @@ class NET_EXPORT ReportingService {
// about report uploads.
virtual bool RequestIsUpload(const URLRequest& request) = 0;
+ virtual const ReportingPolicy& GetPolicy() const = 0;
+
protected:
ReportingService() {}
diff --git a/chromium/net/reporting/reporting_service_unittest.cc b/chromium/net/reporting/reporting_service_unittest.cc
index 24ebceda354..65e1a651d6a 100644
--- a/chromium/net/reporting/reporting_service_unittest.cc
+++ b/chromium/net/reporting/reporting_service_unittest.cc
@@ -59,8 +59,9 @@ TEST_F(ReportingServiceTest, QueueReport) {
}
TEST_F(ReportingServiceTest, ProcessHeader) {
- service()->ProcessHeader(kUrl_, "{\"url\":\"" + kEndpoint_.spec() +
- "\","
+ service()->ProcessHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" +
+ kEndpoint_.spec() +
+ "\"}],"
"\"group\":\"" +
kGroup_ +
"\","
diff --git a/chromium/net/reporting/reporting_test_util.cc b/chromium/net/reporting/reporting_test_util.cc
index 17671b21a80..47c29f5e124 100644
--- a/chromium/net/reporting/reporting_test_util.cc
+++ b/chromium/net/reporting/reporting_test_util.cc
@@ -118,8 +118,28 @@ bool TestReportingDelegate::CanQueueReport(const url::Origin& origin) const {
return true;
}
-bool TestReportingDelegate::CanSendReport(const url::Origin& origin) const {
- return true;
+void TestReportingDelegate::CanSendReports(
+ std::set<url::Origin> origins,
+ base::OnceCallback<void(std::set<url::Origin>)> result_callback) const {
+ if (pause_permissions_check_) {
+ saved_origins_ = std::move(origins);
+ permissions_check_callback_ = std::move(result_callback);
+ return;
+ }
+
+ if (disallow_report_uploads_)
+ origins.clear();
+ std::move(result_callback).Run(std::move(origins));
+}
+
+bool TestReportingDelegate::PermissionsCheckPaused() const {
+ return !permissions_check_callback_.is_null();
+}
+
+void TestReportingDelegate::ResumePermissionsCheck() {
+ if (disallow_report_uploads_)
+ saved_origins_.clear();
+ std::move(permissions_check_callback_).Run(std::move(saved_origins_));
}
bool TestReportingDelegate::CanSetClient(const url::Origin& origin,
@@ -132,6 +152,17 @@ bool TestReportingDelegate::CanUseClient(const url::Origin& origin,
return true;
}
+void TestReportingDelegate::ParseJson(
+ const std::string& unsafe_json,
+ const JsonSuccessCallback& success_callback,
+ const JsonFailureCallback& failure_callback) const {
+ std::unique_ptr<base::Value> value = base::JSONReader::Read(unsafe_json);
+ if (value)
+ success_callback.Run(std::move(value));
+ else
+ failure_callback.Run();
+}
+
TestReportingContext::TestReportingContext(base::Clock* clock,
base::TickClock* tick_clock,
const ReportingPolicy& policy)
diff --git a/chromium/net/reporting/reporting_test_util.h b/chromium/net/reporting/reporting_test_util.h
index f2dff8fb6a1..d4e675aa93f 100644
--- a/chromium/net/reporting/reporting_test_util.h
+++ b/chromium/net/reporting/reporting_test_util.h
@@ -6,6 +6,7 @@
#define NET_REPORTING_REPORTING_TEST_UTIL_H_
#include <memory>
+#include <set>
#include <string>
#include <vector>
@@ -89,9 +90,22 @@ class TestReportingDelegate : public ReportingDelegate {
~TestReportingDelegate() override;
+ void set_disallow_report_uploads(bool disallow_report_uploads) {
+ disallow_report_uploads_ = disallow_report_uploads;
+ }
+
+ void set_pause_permissions_check(bool pause_permissions_check) {
+ pause_permissions_check_ = pause_permissions_check;
+ }
+
bool CanQueueReport(const url::Origin& origin) const override;
- bool CanSendReport(const url::Origin& origin) const override;
+ void CanSendReports(std::set<url::Origin> origins,
+ base::OnceCallback<void(std::set<url::Origin>)>
+ result_callback) const override;
+
+ bool PermissionsCheckPaused() const;
+ void ResumePermissionsCheck();
bool CanSetClient(const url::Origin& origin,
const GURL& endpoint) const override;
@@ -99,7 +113,18 @@ class TestReportingDelegate : public ReportingDelegate {
bool CanUseClient(const url::Origin& origin,
const GURL& endpoint) const override;
+ void ParseJson(const std::string& unsafe_json,
+ const JsonSuccessCallback& success_callback,
+ const JsonFailureCallback& failure_callback) const override;
+
private:
+ bool disallow_report_uploads_ = false;
+ bool pause_permissions_check_ = false;
+
+ mutable std::set<url::Origin> saved_origins_;
+ mutable base::OnceCallback<void(std::set<url::Origin>)>
+ permissions_check_callback_;
+
DISALLOW_COPY_AND_ASSIGN(TestReportingDelegate);
};