diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-03 13:42:47 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:27:51 +0000 |
commit | 8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (patch) | |
tree | d29d987c4d7b173cf853279b79a51598f104b403 /chromium/net/reporting | |
parent | 830c9e163d31a9180fadca926b3e1d7dfffb5021 (diff) | |
download | qtwebengine-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')
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); }; |