Reporting: Wrap context in service.

Reporting is a spec for delivering out-of-band reports from various
other parts of the browser. See http://wicg.github.io/reporting/ for
the spec, or https://goo.gl/pygX5I for details of the planned
implementation in Chromium.

This wraps the context in a service that keeps the implementation
details of Reporting private while implementing and exposing the
high-level operations that other components require from it.

BUG=704259

Review-Url: https://codereview.chromium.org/2770443002
Cr-Commit-Position: refs/heads/master@{#462943}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index ab6d8e64..29528af 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1415,6 +1415,8 @@
       "reporting/reporting_policy.h",
       "reporting/reporting_report.cc",
       "reporting/reporting_report.h",
+      "reporting/reporting_service.cc",
+      "reporting/reporting_service.h",
       "reporting/reporting_uploader.cc",
       "reporting/reporting_uploader.h",
       "sdch/sdch_owner.cc",
@@ -4634,6 +4636,7 @@
     "reporting/reporting_delivery_agent_unittest.cc",
     "reporting/reporting_endpoint_manager_unittest.cc",
     "reporting/reporting_header_parser_unittest.cc",
+    "reporting/reporting_service_unittest.cc",
     "reporting/reporting_test_util.cc",
     "reporting/reporting_test_util.h",
     "reporting/reporting_uploader_unittest.cc",
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc
new file mode 100644
index 0000000..128c510
--- /dev/null
+++ b/net/reporting/reporting_service.cc
@@ -0,0 +1,70 @@
+// 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_service.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "net/reporting/reporting_cache.h"
+#include "net/reporting/reporting_context.h"
+#include "net/reporting/reporting_delegate.h"
+#include "net/reporting/reporting_header_parser.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+class ReportingServiceImpl : public ReportingService {
+ public:
+  ReportingServiceImpl(std::unique_ptr<ReportingContext> context)
+      : context_(std::move(context)) {}
+
+  ~ReportingServiceImpl() override {}
+
+  void QueueReport(const GURL& url,
+                   const std::string& group,
+                   const std::string& type,
+                   std::unique_ptr<const base::Value> body) override {
+    context_->cache()->AddReport(url, group, type, std::move(body),
+                                 context_->tick_clock()->NowTicks(), 0);
+  }
+
+  void ProcessHeader(const GURL& url,
+                     const std::string& header_value) override {
+    ReportingHeaderParser::ParseHeader(context_.get(), url, header_value);
+  }
+
+ private:
+  std::unique_ptr<ReportingContext> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReportingServiceImpl);
+};
+
+}  // namespace
+
+ReportingService::~ReportingService() {}
+
+// static
+std::unique_ptr<ReportingService> ReportingService::Create(
+    const ReportingPolicy& policy,
+    URLRequestContext* request_context,
+    std::unique_ptr<ReportingDelegate> delegate) {
+  return base::MakeUnique<ReportingServiceImpl>(
+      ReportingContext::Create(policy, std::move(delegate), request_context));
+}
+
+// static
+std::unique_ptr<ReportingService> ReportingService::CreateForTesting(
+    std::unique_ptr<ReportingContext> reporting_context) {
+  return base::MakeUnique<ReportingServiceImpl>(std::move(reporting_context));
+}
+
+}  // namespace net
diff --git a/net/reporting/reporting_service.h b/net/reporting/reporting_service.h
new file mode 100644
index 0000000..c305410
--- /dev/null
+++ b/net/reporting/reporting_service.h
@@ -0,0 +1,74 @@
+// 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_SERVICE_H_
+#define NET_REPORTING_REPORTING_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+
+class GURL;
+
+namespace base {
+class Value;
+}  // namespace
+
+namespace net {
+
+class ReportingContext;
+class ReportingDelegate;
+struct ReportingPolicy;
+class URLRequestContext;
+
+// The external interface to the Reporting system, used by the embedder of //net
+// and also other parts of //net.
+class NET_EXPORT ReportingService {
+ public:
+  virtual ~ReportingService();
+
+  // Creates a ReportingService. |policy| will be copied. |request_context| must
+  // outlive the ReportingService. The ReportingService will take ownership of
+  // |delegate| and destroy it when the service is destroyed.
+  static std::unique_ptr<ReportingService> Create(
+      const ReportingPolicy& policy,
+      URLRequestContext* request_context,
+      std::unique_ptr<ReportingDelegate> delegate);
+
+  // Creates a ReportingService for testing purposes using an
+  // already-constructed ReportingContext. The ReportingService will take
+  // ownership of |reporting_context| and destroy it when the service is
+  // destroyed.
+  static std::unique_ptr<ReportingService> CreateForTesting(
+      std::unique_ptr<ReportingContext> reporting_context);
+
+  // Queues a report for delivery. |url| is the URL that originated the report.
+  // |group| is the endpoint group to which the report should be delivered.
+  // |type| is the type of the report. |body| is the body of the report.
+  //
+  // The Reporting system will take ownership of |body|; all other parameters
+  // will be copied.
+  virtual void QueueReport(const GURL& url,
+                           const std::string& group,
+                           const std::string& type,
+                           std::unique_ptr<const base::Value> body) = 0;
+
+  // Processes a Report-To header. |url| is the URL that originated the header;
+  // |header_value| is the normalized value of the Report-To header.
+  virtual void ProcessHeader(const GURL& url,
+                             const std::string& header_value) = 0;
+
+ protected:
+  ReportingService() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReportingService);
+};
+
+}  // namespace net
+
+#endif  // NET_REPORTING_REPORTING_SERVICE_H_
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc
new file mode 100644
index 0000000..20c8656
--- /dev/null
+++ b/net/reporting/reporting_service_unittest.cc
@@ -0,0 +1,78 @@
+// 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_service.h"
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ptr_util.h"
+#include "base/time/tick_clock.h"
+#include "base/values.h"
+#include "net/reporting/reporting_cache.h"
+#include "net/reporting/reporting_context.h"
+#include "net/reporting/reporting_delegate.h"
+#include "net/reporting/reporting_policy.h"
+#include "net/reporting/reporting_report.h"
+#include "net/reporting/reporting_service.h"
+#include "net/reporting/reporting_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+class ReportingServiceTest : public ::testing::Test {
+ protected:
+  const GURL kUrl_ = GURL("https://origin/path");
+  const url::Origin kOrigin_ = url::Origin(kUrl_);
+  const GURL kEndpoint_ = GURL("https://endpoint/");
+  const std::string kGroup_ = "group";
+  const std::string kType_ = "type";
+
+  ReportingServiceTest()
+      : context_(new TestReportingContext(ReportingPolicy())),
+        service_(
+            ReportingService::CreateForTesting(base::WrapUnique(context_))) {}
+
+  TestReportingContext* context() { return context_; }
+  ReportingService* service() { return service_.get(); }
+
+ private:
+  TestReportingContext* context_;
+  std::unique_ptr<ReportingService> service_;
+};
+
+TEST_F(ReportingServiceTest, QueueReport) {
+  service()->QueueReport(kUrl_, kGroup_, kType_,
+                         base::MakeUnique<base::DictionaryValue>());
+
+  std::vector<const ReportingReport*> reports;
+  context()->cache()->GetReports(&reports);
+  ASSERT_EQ(1u, reports.size());
+  EXPECT_EQ(kUrl_, reports[0]->url);
+  EXPECT_EQ(kGroup_, reports[0]->group);
+  EXPECT_EQ(kType_, reports[0]->type);
+}
+
+TEST_F(ReportingServiceTest, ProcessHeader) {
+  service()->ProcessHeader(kUrl_, "{\"url\":\"" + kEndpoint_.spec() +
+                                      "\","
+                                      "\"group\":\"" +
+                                      kGroup_ +
+                                      "\","
+                                      "\"max-age\":86400}");
+
+  const ReportingClient* client =
+      FindClientInCache(context()->cache(), kOrigin_, kEndpoint_);
+  ASSERT_TRUE(client != nullptr);
+  EXPECT_EQ(kOrigin_, client->origin);
+  EXPECT_EQ(kEndpoint_, client->endpoint);
+  EXPECT_EQ(ReportingClient::Subdomains::EXCLUDE, client->subdomains);
+  EXPECT_EQ(kGroup_, client->group);
+  EXPECT_EQ(context()->tick_clock()->NowTicks() + base::TimeDelta::FromDays(1),
+            client->expires);
+}
+
+}  // namespace
+}  // namespace net