Reporting: Fill in user_agent field in reports

Per https://github.com/w3c/reporting/issues/52, we are now supposed to
include the User-Agent string of the original request in any reports
generated about that request.

TBR=markusheintz@chromium.org

Bug: 865394
Cq-Include-Trybots: luci.chromium.try:linux_mojo
Change-Id: Ib49244399ed05398d598da1d02131153dd509306
Reviewed-on: https://chromium-review.googlesource.com/1140203
Commit-Queue: Douglas Creager <dcreager@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Misha Efimov <mef@chromium.org>
Cr-Commit-Position: refs/heads/master@{#576599}
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 39c460c7..af54b0e 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -988,6 +988,7 @@
   ~MockReportingService() override = default;
 
   void QueueReport(const GURL& url,
+                   const std::string& user_agent,
                    const std::string& group,
                    const std::string& type,
                    std::unique_ptr<const base::Value> body,
diff --git a/chrome/browser/net/reporting_browsertest.cc b/chrome/browser/net/reporting_browsertest.cc
index 28c3fe85..ce4eea42 100644
--- a/chrome/browser/net/reporting_browsertest.cc
+++ b/chrome/browser/net/reporting_browsertest.cc
@@ -113,6 +113,10 @@
   for (auto& report : parsed_payload->GetList()) {
     report.RemoveKey("age");
     report.RemovePath({"body", "elapsed_time"});
+    auto* user_agent =
+        report.FindKeyOfType("user_agent", base::Value::Type::STRING);
+    if (user_agent != nullptr)
+      *user_agent = base::Value("Mozilla/1.0");
   }
   return parsed_payload;
 }
@@ -155,6 +159,7 @@
             },
             "type": "network-error",
             "url": "https://example.com:%d/original",
+            "user_agent": "Mozilla/1.0",
           },
         ]
       )json",
diff --git a/content/browser/net/reporting_service_proxy.cc b/content/browser/net/reporting_service_proxy.cc
index b231bd7..6f525514 100644
--- a/content/browser/net/reporting_service_proxy.cc
+++ b/content/browser/net/reporting_service_proxy.cc
@@ -16,6 +16,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/reporting/reporting_report.h"
 #include "net/reporting/reporting_service.h"
+#include "net/url_request/http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "third_party/blink/public/platform/reporting.mojom.h"
@@ -125,7 +126,11 @@
 
     // Depth is only non-zero for NEL reports, and those can't come from the
     // renderer.
-    reporting_service->QueueReport(url, group, type, std::move(body),
+    std::string user_agent;
+    if (request_context->http_user_agent_settings() != nullptr)
+      user_agent = request_context->http_user_agent_settings()->GetUserAgent();
+    reporting_service->QueueReport(url, user_agent, group, type,
+                                   std::move(body),
                                    /* depth= */ 0);
   }
 
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index b694d19..1a95e58 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -307,7 +307,7 @@
     }
 
     reporting_service_->QueueReport(
-        details.uri, policy->report_to, kReportType,
+        details.uri, details.user_agent, policy->report_to, kReportType,
         CreateReportBody(phase_string, type_string, sampling_fraction, details),
         details.reporting_upload_depth);
     RecordRequestOutcome(RequestOutcome::QUEUED);
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h
index cfb4968..058c0ad2 100644
--- a/net/network_error_logging/network_error_logging_service.h
+++ b/net/network_error_logging/network_error_logging_service.h
@@ -53,6 +53,7 @@
 
     GURL uri;
     GURL referrer;
+    std::string user_agent;
     IPAddress server_ip;
     std::string protocol;
     std::string method;
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 86574e0..da785393 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -33,17 +33,20 @@
 
     Report(Report&& other)
         : url(other.url),
+          user_agent(other.user_agent),
           group(other.group),
           type(other.type),
           body(std::move(other.body)),
           depth(other.depth) {}
 
     Report(const GURL& url,
+           const std::string& user_agent,
            const std::string& group,
            const std::string& type,
            std::unique_ptr<const base::Value> body,
            int depth)
         : url(url),
+          user_agent(user_agent),
           group(group),
           type(type),
           body(std::move(body)),
@@ -52,6 +55,7 @@
     ~Report() = default;
 
     GURL url;
+    std::string user_agent;
     std::string group;
     std::string type;
     std::unique_ptr<const base::Value> body;
@@ -70,11 +74,13 @@
   ~TestReportingService() override = default;
 
   void QueueReport(const GURL& url,
+                   const std::string& user_agent,
                    const std::string& group,
                    const std::string& type,
                    std::unique_ptr<const base::Value> body,
                    int depth) override {
-    reports_.push_back(Report(url, group, type, std::move(body), depth));
+    reports_.push_back(
+        Report(url, user_agent, group, type, std::move(body), depth));
   }
 
   void ProcessHeader(const GURL& url,
@@ -139,6 +145,7 @@
 
     details.uri = url;
     details.referrer = kReferrer_;
+    details.user_agent = kUserAgent_;
     details.server_ip = server_ip.IsValid() ? server_ip : kServerIP_;
     details.method = std::move(method);
     details.status_code = status_code;
@@ -179,6 +186,7 @@
       "{\"report_to\":\"group\",\"max_age\":86400,\"junk\":[[[[[[[[[[]]]]]]]]]]"
       "}";
 
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup_ = "group";
 
   const std::string kType_ = NetworkErrorLoggingService::kReportType;
@@ -254,6 +262,7 @@
 
   ASSERT_EQ(1u, reports().size());
   EXPECT_EQ(kUrl_, reports()[0].url);
+  EXPECT_EQ(kUserAgent_, reports()[0].user_agent);
   EXPECT_EQ(kGroup_, reports()[0].group);
   EXPECT_EQ(kType_, reports()[0].type);
   EXPECT_EQ(0, reports()[0].depth);
@@ -290,6 +299,7 @@
 
   ASSERT_EQ(1u, reports().size());
   EXPECT_EQ(kUrl_, reports()[0].url);
+  EXPECT_EQ(kUserAgent_, reports()[0].user_agent);
   EXPECT_EQ(kGroup_, reports()[0].group);
   EXPECT_EQ(kType_, reports()[0].type);
   EXPECT_EQ(0, reports()[0].depth);
@@ -326,6 +336,7 @@
 
   ASSERT_EQ(1u, reports().size());
   EXPECT_EQ(kUrl_, reports()[0].url);
+  EXPECT_EQ(kUserAgent_, reports()[0].user_agent);
   EXPECT_EQ(kGroup_, reports()[0].group);
   EXPECT_EQ(kType_, reports()[0].type);
   EXPECT_EQ(0, reports()[0].depth);
diff --git a/net/reporting/reporting_browsing_data_remover_unittest.cc b/net/reporting/reporting_browsing_data_remover_unittest.cc
index 0704806..d32128b3 100644
--- a/net/reporting/reporting_browsing_data_remover_unittest.cc
+++ b/net/reporting/reporting_browsing_data_remover_unittest.cc
@@ -41,7 +41,7 @@
   }
 
   void AddReport(const GURL& url) {
-    cache()->AddReport(url, kGroup_, kType_,
+    cache()->AddReport(url, kUserAgent_, kGroup_, kType_,
                        std::make_unique<base::DictionaryValue>(), 0,
                        tick_clock()->NowTicks(), 0);
   }
@@ -74,6 +74,7 @@
   const url::Origin kOrigin1_ = url::Origin::Create(kUrl1_);
   const url::Origin kOrigin2_ = url::Origin::Create(kUrl2_);
   const GURL kEndpoint_ = GURL("https://endpoint/");
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup_ = "group";
   const std::string kType_ = "default";
 };
diff --git a/net/reporting/reporting_cache.cc b/net/reporting/reporting_cache.cc
index 3f30793..9756fc9 100644
--- a/net/reporting/reporting_cache.cc
+++ b/net/reporting/reporting_cache.cc
@@ -71,6 +71,7 @@
   }
 
   void AddReport(const GURL& url,
+                 const std::string& user_agent,
                  const std::string& group,
                  const std::string& type,
                  std::unique_ptr<const base::Value> body,
@@ -78,7 +79,7 @@
                  base::TimeTicks queued,
                  int attempts) override {
     auto report = std::make_unique<ReportingReport>(
-        url, group, type, std::move(body), depth, queued, attempts);
+        url, user_agent, group, type, std::move(body), depth, queued, attempts);
 
     auto inserted =
         reports_.insert(std::make_pair(report.get(), std::move(report)));
diff --git a/net/reporting/reporting_cache.h b/net/reporting/reporting_cache.h
index eda09b3..18ed839 100644
--- a/net/reporting/reporting_cache.h
+++ b/net/reporting/reporting_cache.h
@@ -60,6 +60,7 @@
   // All parameters correspond to the desired values for the relevant fields in
   // ReportingReport.
   virtual void AddReport(const GURL& url,
+                         const std::string& user_agent,
                          const std::string& group,
                          const std::string& type,
                          std::unique_ptr<const base::Value> body,
diff --git a/net/reporting/reporting_cache_unittest.cc b/net/reporting/reporting_cache_unittest.cc
index 6d4dd30..93fd1e6 100644
--- a/net/reporting/reporting_cache_unittest.cc
+++ b/net/reporting/reporting_cache_unittest.cc
@@ -77,6 +77,7 @@
   // Adds a new report to the cache, and returns it.
   const ReportingReport* AddAndReturnReport(
       const GURL& url,
+      const std::string& user_agent,
       const std::string& group,
       const std::string& type,
       std::unique_ptr<const base::Value> body,
@@ -91,8 +92,8 @@
     // in test cases, so I've optimized for readability over execution speed.
     std::vector<const ReportingReport*> before;
     cache()->GetReports(&before);
-    cache()->AddReport(url, group, type, std::move(body), depth, queued,
-                       attempts);
+    cache()->AddReport(url, user_agent, group, type, std::move(body), depth,
+                       queued, attempts);
     std::vector<const ReportingReport*> after;
     cache()->GetReports(&after);
 
@@ -101,6 +102,7 @@
       if (std::find(before.begin(), before.end(), report) == before.end()) {
         // Sanity check the result before we return it.
         EXPECT_EQ(url, report->url);
+        EXPECT_EQ(user_agent, report->user_agent);
         EXPECT_EQ(group, report->group);
         EXPECT_EQ(type, report->type);
         EXPECT_EQ(*body_unowned, *report->body);
@@ -123,6 +125,7 @@
   const url::Origin kOrigin2_ = url::Origin::Create(GURL("https://origin2/"));
   const GURL kEndpoint1_ = GURL("https://endpoint1/");
   const GURL kEndpoint2_ = GURL("https://endpoint2/");
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup1_ = "group1";
   const std::string kGroup2 = "group2";
   const std::string kType_ = "default";
@@ -139,7 +142,7 @@
   cache()->GetReports(&reports);
   EXPECT_TRUE(reports.empty());
 
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
   EXPECT_EQ(1, observer()->cache_update_count());
 
@@ -148,6 +151,7 @@
   const ReportingReport* report = reports[0];
   ASSERT_TRUE(report);
   EXPECT_EQ(kUrl1_, report->url);
+  EXPECT_EQ(kUserAgent_, report->user_agent);
   EXPECT_EQ(kGroup1_, report->group);
   EXPECT_EQ(kType_, report->type);
   // TODO(juliatuttle): Check body?
@@ -173,9 +177,9 @@
 }
 
 TEST_F(ReportingCacheTest, RemoveAllReports) {
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
   EXPECT_EQ(2, observer()->cache_update_count());
 
@@ -191,7 +195,7 @@
 }
 
 TEST_F(ReportingCacheTest, RemovePendingReports) {
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
   EXPECT_EQ(1, observer()->cache_update_count());
 
@@ -222,7 +226,7 @@
 }
 
 TEST_F(ReportingCacheTest, RemoveAllPendingReports) {
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
   EXPECT_EQ(1, observer()->cache_update_count());
 
@@ -255,16 +259,18 @@
 TEST_F(ReportingCacheTest, GetReportsAsValue) {
   // We need a reproducible expiry timestamp for this test case.
   const base::TimeTicks now = base::TimeTicks();
-  const ReportingReport* report1 = AddAndReturnReport(
-      kUrl1_, kGroup1_, kType_, std::make_unique<base::DictionaryValue>(), 0,
-      now + base::TimeDelta::FromSeconds(200), 0);
-  const ReportingReport* report2 = AddAndReturnReport(
-      kUrl1_, kGroup2, kType_, std::make_unique<base::DictionaryValue>(), 0,
-      now + base::TimeDelta::FromSeconds(100), 1);
-  cache()->AddReport(kUrl2_, kGroup1_, kType_,
+  const ReportingReport* report1 =
+      AddAndReturnReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
+                         std::make_unique<base::DictionaryValue>(), 0,
+                         now + base::TimeDelta::FromSeconds(200), 0);
+  const ReportingReport* report2 =
+      AddAndReturnReport(kUrl1_, kUserAgent_, kGroup2, kType_,
+                         std::make_unique<base::DictionaryValue>(), 0,
+                         now + base::TimeDelta::FromSeconds(100), 1);
+  cache()->AddReport(kUrl2_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 2,
                      now + base::TimeDelta::FromSeconds(200), 0);
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      now + base::TimeDelta::FromSeconds(300), 0);
   // Mark report1 as pending as report2 as doomed
@@ -570,7 +576,7 @@
 
   // Enqueue the maximum number of reports, spaced apart in time.
   for (size_t i = 0; i < max_report_count; ++i) {
-    cache()->AddReport(kUrl1_, kGroup1_, kType_,
+    cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                        std::make_unique<base::DictionaryValue>(), 0,
                        tick_clock()->NowTicks(), 0);
     tick_clock()->Advance(base::TimeDelta::FromMinutes(1));
@@ -578,7 +584,7 @@
   EXPECT_EQ(max_report_count, report_count());
 
   // Add one more report to force the cache to evict one.
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
 
   // Make sure the cache evicted a report to make room for the new one, and make
@@ -598,7 +604,7 @@
 
   // Enqueue the maximum number of reports, spaced apart in time.
   for (size_t i = 0; i < max_report_count; ++i) {
-    cache()->AddReport(kUrl1_, kGroup1_, kType_,
+    cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                        std::make_unique<base::DictionaryValue>(), 0,
                        tick_clock()->NowTicks(), 0);
     tick_clock()->Advance(base::TimeDelta::FromMinutes(1));
@@ -612,7 +618,7 @@
 
   // Add one more report to force the cache to evict one. Since the cache has
   // only pending reports, it will be forced to evict the *new* report!
-  cache()->AddReport(kUrl1_, kGroup1_, kType_,
+  cache()->AddReport(kUrl1_, kUserAgent_, kGroup1_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0, kNow_, 0);
 
   // Make sure the cache evicted a report, and make sure the report evicted was
diff --git a/net/reporting/reporting_delivery_agent.cc b/net/reporting/reporting_delivery_agent.cc
index e2d2f766..a0f87af 100644
--- a/net/reporting/reporting_delivery_agent.cc
+++ b/net/reporting/reporting_delivery_agent.cc
@@ -41,6 +41,7 @@
     report_value->SetInteger("age", (now - report->queued).InMilliseconds());
     report_value->SetString("type", report->type);
     report_value->SetString("url", report->url.spec());
+    report_value->SetString("user_agent", report->user_agent);
     report_value->SetKey("body", report->body->Clone());
 
     reports_value.Append(std::move(report_value));
diff --git a/net/reporting/reporting_delivery_agent_unittest.cc b/net/reporting/reporting_delivery_agent_unittest.cc
index d58393a..7f87e30 100644
--- a/net/reporting/reporting_delivery_agent_unittest.cc
+++ b/net/reporting/reporting_delivery_agent_unittest.cc
@@ -56,6 +56,7 @@
   const GURL kSubdomainUrl_ = GURL("https://sub.origin/path");
   const url::Origin kOrigin_ = url::Origin::Create(GURL("https://origin/"));
   const GURL kEndpoint_ = GURL("https://endpoint/");
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup_ = "group";
   const std::string kType_ = "type";
 };
@@ -65,8 +66,8 @@
   body.SetString("key", "value");
 
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
-                     tick_clock()->NowTicks(), 0);
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_, body.CreateDeepCopy(),
+                     0, tick_clock()->NowTicks(), 0);
 
   // Upload is automatically started when cache is modified.
 
@@ -81,11 +82,12 @@
 
     base::DictionaryValue* report;
     ASSERT_TRUE(list->GetDictionary(0, &report));
-    EXPECT_EQ(4u, report->size());
+    EXPECT_EQ(5u, report->size());
 
     ExpectDictIntegerValue(0, *report, "age");
     ExpectDictStringValue(kType_, *report, "type");
     ExpectDictStringValue(kUrl_.spec(), *report, "url");
+    ExpectDictStringValue(kUserAgent_, *report, "user_agent");
     ExpectDictDictionaryValue(body, *report, "body");
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
@@ -113,8 +115,8 @@
 
   SetClient(kOrigin_, kEndpoint_, kGroup_,
             ReportingClient::Subdomains::INCLUDE);
-  cache()->AddReport(kSubdomainUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
-                     tick_clock()->NowTicks(), 0);
+  cache()->AddReport(kSubdomainUrl_, kUserAgent_, kGroup_, kType_,
+                     body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0);
 
   // Upload is automatically started when cache is modified.
 
@@ -129,11 +131,12 @@
 
     base::DictionaryValue* report;
     ASSERT_TRUE(list->GetDictionary(0, &report));
-    EXPECT_EQ(4u, report->size());
+    EXPECT_EQ(5u, report->size());
 
     ExpectDictIntegerValue(0, *report, "age");
     ExpectDictStringValue(kType_, *report, "type");
     ExpectDictStringValue(kSubdomainUrl_.spec(), *report, "url");
+    ExpectDictStringValue(kUserAgent_, *report, "user_agent");
     ExpectDictDictionaryValue(body, *report, "body");
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
@@ -162,8 +165,8 @@
 
   SetClient(kOrigin_, kEndpoint_, kGroup_,
             ReportingClient::Subdomains::INCLUDE);
-  cache()->AddReport(kSubdomainUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
-                     tick_clock()->NowTicks(), 0);
+  cache()->AddReport(kSubdomainUrl_, kUserAgent_, kGroup_, kType_,
+                     body.CreateDeepCopy(), 0, tick_clock()->NowTicks(), 0);
 
   // Upload is automatically started when cache is modified.
 
@@ -194,13 +197,13 @@
 
   // Trigger and complete an upload to start the delivery timer.
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
-                     tick_clock()->NowTicks(), 0);
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_, body.CreateDeepCopy(),
+                     0, tick_clock()->NowTicks(), 0);
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
 
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
-                     tick_clock()->NowTicks(), 0);
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_, body.CreateDeepCopy(),
+                     0, tick_clock()->NowTicks(), 0);
 
   EXPECT_TRUE(delivery_timer()->IsRunning());
   delivery_timer()->Fire();
@@ -216,11 +219,12 @@
 
     base::DictionaryValue* report;
     ASSERT_TRUE(list->GetDictionary(0, &report));
-    EXPECT_EQ(4u, report->size());
+    EXPECT_EQ(5u, report->size());
 
     ExpectDictIntegerValue(0, *report, "age");
     ExpectDictStringValue(kType_, *report, "type");
     ExpectDictStringValue(kUrl_.spec(), *report, "url");
+    ExpectDictStringValue(kUserAgent_, *report, "user_agent");
     ExpectDictDictionaryValue(body, *report, "body");
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
@@ -244,7 +248,7 @@
 
 TEST_F(ReportingDeliveryAgentTest, FailedUpload) {
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -297,8 +301,8 @@
   body.SetString("key", "value");
 
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_, body.CreateDeepCopy(), 0,
-                     tick_clock()->NowTicks(), 0);
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_, body.CreateDeepCopy(),
+                     0, tick_clock()->NowTicks(), 0);
 
   tick_clock()->Advance(base::TimeDelta::FromMilliseconds(kAgeMillis));
 
@@ -333,7 +337,7 @@
   ASSERT_TRUE(FindClientInCache(cache(), kOrigin_, kEndpoint_));
   ASSERT_TRUE(FindClientInCache(cache(), kDifferentOrigin, kEndpoint_));
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -362,7 +366,7 @@
 
 TEST_F(ReportingDeliveryAgentTest, ConcurrentRemove) {
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -401,7 +405,7 @@
   context()->test_delegate()->set_pause_permissions_check(true);
 
   SetClient(kOrigin_, kEndpoint_, kGroup_);
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -444,17 +448,17 @@
   SetClient(kDifferentOrigin, kEndpoint_, kGroup_);
 
   // Trigger and complete an upload to start the delivery timer.
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
 
   // Now that the delivery timer is running, these reports won't be immediately
   // uploaded.
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
-  cache()->AddReport(kDifferentUrl, kGroup_, kType_,
+  cache()->AddReport(kDifferentUrl, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   EXPECT_EQ(0u, pending_uploads().size());
@@ -477,7 +481,7 @@
 TEST_F(ReportingDeliveryAgentTest, SerializeUploadsToEndpoint) {
   SetClient(kOrigin_, kEndpoint_, kGroup_);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -485,7 +489,7 @@
   delivery_timer()->Fire();
   EXPECT_EQ(1u, pending_uploads().size());
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -513,7 +517,7 @@
   SetClient(kOrigin_, kEndpoint_, kGroup_);
   SetClient(kOrigin_, kDifferentEndpoint, kGroup_);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -521,7 +525,7 @@
   delivery_timer()->Fire();
   EXPECT_EQ(1u, pending_uploads().size());
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -549,10 +553,10 @@
   SetClient(kOrigin_, kEndpoint_, kGroup_);
   SetClient(kOrigin_, kDifferentEndpoint, kDifferentGroup);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
-  cache()->AddReport(kUrl_, kDifferentGroup, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kDifferentGroup, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
diff --git a/net/reporting/reporting_garbage_collector_unittest.cc b/net/reporting/reporting_garbage_collector_unittest.cc
index 5ae177b..78ad1601 100644
--- a/net/reporting/reporting_garbage_collector_unittest.cc
+++ b/net/reporting/reporting_garbage_collector_unittest.cc
@@ -27,6 +27,7 @@
   }
 
   const GURL kUrl_ = GURL("https://origin/path");
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup_ = "group";
   const std::string kType_ = "default";
 };
@@ -40,7 +41,7 @@
 TEST_F(ReportingGarbageCollectorTest, Timer) {
   EXPECT_FALSE(garbage_collection_timer()->IsRunning());
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
@@ -52,7 +53,7 @@
 }
 
 TEST_F(ReportingGarbageCollectorTest, Report) {
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   garbage_collection_timer()->Fire();
@@ -61,7 +62,7 @@
 }
 
 TEST_F(ReportingGarbageCollectorTest, ExpiredReport) {
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   tick_clock()->Advance(2 * policy().max_report_age);
@@ -71,7 +72,7 @@
 }
 
 TEST_F(ReportingGarbageCollectorTest, FailedReport) {
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
 
diff --git a/net/reporting/reporting_network_change_observer_unittest.cc b/net/reporting/reporting_network_change_observer_unittest.cc
index db1aabc..c5610d0 100644
--- a/net/reporting/reporting_network_change_observer_unittest.cc
+++ b/net/reporting/reporting_network_change_observer_unittest.cc
@@ -54,6 +54,7 @@
   const GURL kUrl_ = GURL("https://origin/path");
   const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
   const GURL kEndpoint_ = GURL("https://endpoint/");
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup_ = "group";
   const std::string kType_ = "default";
 };
@@ -64,7 +65,7 @@
   new_policy.persist_clients_across_network_changes = true;
   UsePolicy(new_policy);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   SetClient();
@@ -83,7 +84,7 @@
   new_policy.persist_clients_across_network_changes = true;
   UsePolicy(new_policy);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   SetClient();
@@ -102,7 +103,7 @@
   new_policy.persist_clients_across_network_changes = false;
   UsePolicy(new_policy);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   SetClient();
@@ -121,7 +122,7 @@
   new_policy.persist_clients_across_network_changes = false;
   UsePolicy(new_policy);
 
-  cache()->AddReport(kUrl_, kGroup_, kType_,
+  cache()->AddReport(kUrl_, kUserAgent_, kGroup_, kType_,
                      std::make_unique<base::DictionaryValue>(), 0,
                      tick_clock()->NowTicks(), 0);
   SetClient();
diff --git a/net/reporting/reporting_report.cc b/net/reporting/reporting_report.cc
index c6dd8204..6818f0d4 100644
--- a/net/reporting/reporting_report.cc
+++ b/net/reporting/reporting_report.cc
@@ -25,6 +25,7 @@
 }  // namespace
 
 ReportingReport::ReportingReport(const GURL& url,
+                                 const std::string& user_agent,
                                  const std::string& group,
                                  const std::string& type,
                                  std::unique_ptr<const base::Value> body,
@@ -32,6 +33,7 @@
                                  base::TimeTicks queued,
                                  int attempts)
     : url(url),
+      user_agent(user_agent),
       group(group),
       type(type),
       body(std::move(body)),
diff --git a/net/reporting/reporting_report.h b/net/reporting/reporting_report.h
index 196be9e..18d329c 100644
--- a/net/reporting/reporting_report.h
+++ b/net/reporting/reporting_report.h
@@ -38,6 +38,7 @@
   };
 
   ReportingReport(const GURL& url,
+                  const std::string& user_agent,
                   const std::string& group,
                   const std::string& type,
                   std::unique_ptr<const base::Value> body,
@@ -55,6 +56,9 @@
   // delivered report.)
   GURL url;
 
+  // The User-Agent header that was used for the request.
+  std::string user_agent;
+
   // The endpoint group that should be used to deliver the report. (Not included
   // in the delivered report.)
   std::string group;
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc
index fc53e4e..58c48541 100644
--- a/net/reporting/reporting_service.cc
+++ b/net/reporting/reporting_service.cc
@@ -34,6 +34,7 @@
   ~ReportingServiceImpl() override = default;
 
   void QueueReport(const GURL& url,
+                   const std::string& user_agent,
                    const std::string& group,
                    const std::string& type,
                    std::unique_ptr<const base::Value> body,
@@ -44,8 +45,8 @@
     if (!context_->delegate()->CanQueueReport(url::Origin::Create(url)))
       return;
 
-    context_->cache()->AddReport(url, group, type, std::move(body), depth,
-                                 context_->tick_clock()->NowTicks(), 0);
+    context_->cache()->AddReport(url, user_agent, group, type, std::move(body),
+                                 depth, context_->tick_clock()->NowTicks(), 0);
   }
 
   void ProcessHeader(const GURL& url,
diff --git a/net/reporting/reporting_service.h b/net/reporting/reporting_service.h
index e30d122..a852d0f 100644
--- a/net/reporting/reporting_service.h
+++ b/net/reporting/reporting_service.h
@@ -45,12 +45,14 @@
       std::unique_ptr<ReportingContext> reporting_context);
 
   // Queues a report for delivery. |url| is the URL that originated the report.
+  // |user_agent| is the User-Agent header that was used for the request.
   // |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& user_agent,
                            const std::string& group,
                            const std::string& type,
                            std::unique_ptr<const base::Value> body,
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc
index 8cf5689..42613ede 100644
--- a/net/reporting/reporting_service_unittest.cc
+++ b/net/reporting/reporting_service_unittest.cc
@@ -27,6 +27,7 @@
   const GURL kUrl_ = GURL("https://origin/path");
   const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
   const GURL kEndpoint_ = GURL("https://endpoint/");
+  const std::string kUserAgent_ = "Mozilla/1.0";
   const std::string kGroup_ = "group";
   const std::string kType_ = "type";
 
@@ -48,13 +49,14 @@
 };
 
 TEST_F(ReportingServiceTest, QueueReport) {
-  service()->QueueReport(kUrl_, kGroup_, kType_,
+  service()->QueueReport(kUrl_, kUserAgent_, kGroup_, kType_,
                          std::make_unique<base::DictionaryValue>(), 0);
 
   std::vector<const ReportingReport*> reports;
   context()->cache()->GetReports(&reports);
   ASSERT_EQ(1u, reports.size());
   EXPECT_EQ(kUrl_, reports[0]->url);
+  EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
   EXPECT_EQ(kGroup_, reports[0]->group);
   EXPECT_EQ(kType_, reports[0]->type);
 }
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index bfd2627..0f5fe6f 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -33,6 +33,7 @@
 #include "net/log/net_log_source_type.h"
 #include "net/socket/next_proto.h"
 #include "net/ssl/ssl_cert_request_info.h"
+#include "net/url_request/http_user_agent_settings.h"
 #include "net/url_request/redirect_info.h"
 #include "net/url_request/redirect_util.h"
 #include "net/url_request/url_request_context.h"
@@ -1178,6 +1179,19 @@
 }
 
 #if BUILDFLAG(ENABLE_REPORTING)
+std::string URLRequest::GetUserAgent() const {
+  // This should be kept in sync with the corresponding code in
+  // URLRequestHttpJob::Start.
+  // TODO(dcreager): Consider whether we can share code instead of copy-pasting
+  std::string user_agent;
+  if (extra_request_headers_.GetHeader(net::HttpRequestHeaders::kUserAgent,
+                                       &user_agent))
+    return user_agent;
+  if (context()->http_user_agent_settings())
+    return context()->http_user_agent_settings()->GetUserAgent();
+  return std::string();
+}
+
 void URLRequest::MaybeGenerateNetworkErrorLoggingReport() {
   NetworkErrorLoggingService* service =
       context()->network_error_logging_service();
@@ -1194,6 +1208,7 @@
 
   details.uri = url();
   details.referrer = GURL(referrer());
+  details.user_agent = GetUserAgent();
   IPEndPoint endpoint;
   if (GetRemoteEndpoint(&endpoint))
     details.server_ip = endpoint.address();
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index b3c59f6a..6f23eed 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -832,6 +832,7 @@
   void OnCallToDelegateComplete();
 
 #if BUILDFLAG(ENABLE_REPORTING)
+  std::string GetUserAgent() const;
   void MaybeGenerateNetworkErrorLoggingReport();
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index ff0bb02..be69cc9 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -443,6 +443,8 @@
 
   request_info_.token_binding_referrer = request_->token_binding_referrer();
 
+  // This should be kept in sync with the corresponding code in
+  // URLRequest::GetUserAgent.
   request_info_.extra_headers.SetHeaderIfMissing(
       HttpRequestHeaders::kUserAgent,
       http_user_agent_settings_ ?
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index f25913bc..5844a82 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -140,7 +140,7 @@
         context_storage_.http_network_session(),
         HttpCache::DefaultBackend::InMemory(0), true /* is_main_cache */));
   }
-  if (!http_user_agent_settings()) {
+  if (!http_user_agent_settings() && create_default_http_user_agent_settings_) {
     context_storage_.set_http_user_agent_settings(
         std::make_unique<StaticHttpUserAgentSettings>("en-us,fr",
                                                       std::string()));
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index feb3153..f6b9249 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -92,6 +92,10 @@
     context_storage_.set_ct_policy_enforcer(std::move(ct_policy_enforcer));
   }
 
+  void set_create_default_http_user_agent_settings(bool value) {
+    create_default_http_user_agent_settings_ = value;
+  }
+
  private:
   bool initialized_ = false;
 
@@ -106,6 +110,8 @@
 
   ProxyDelegate* proxy_delegate_ = nullptr;
 
+  bool create_default_http_user_agent_settings_ = true;
+
  protected:
   URLRequestContextStorage context_storage_;
 };
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 478e912..147539d 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -7482,6 +7482,7 @@
   ~TestReportingService() override = default;
 
   void QueueReport(const GURL& url,
+                   const std::string& user_agent,
                    const std::string& group,
                    const std::string& type,
                    std::unique_ptr<const base::Value> body,
@@ -7694,6 +7695,11 @@
   return std::make_unique<test_server::RawHttpResponse>("", "");
 }
 
+// Distinct User-Agent header values that we use to ensure that URLRequest
+// passes along user agents into NEL reports correctly.
+constexpr char kHeaderUserAgent[] = "MozillaFromHeader/1.0";
+constexpr char kSettingsUserAgent[] = "MozillaFromSettings/1.0";
+
 }  // namespace
 
 TEST_F(URLRequestTestHTTP, DontProcessNelHeaderNoDelegate) {
@@ -7890,6 +7896,102 @@
   EXPECT_EQ(ERR_EMPTY_RESPONSE, nel_service.errors()[0].type);
 }
 
+TEST_F(URLRequestTestHTTP, NelReportUserAgentWithHeaderWithSettings) {
+  EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  ASSERT_TRUE(https_test_server.Start());
+  GURL request_url = https_test_server.base_url();
+
+  StaticHttpUserAgentSettings settings("en", kSettingsUserAgent);
+  TestNetworkDelegate network_delegate;
+  TestNetworkErrorLoggingService nel_service;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_network_error_logging_service(&nel_service);
+  context.set_http_user_agent_settings(&settings);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->SetExtraRequestHeaderByName("User-Agent", kHeaderUserAgent, true);
+  request->Start();
+  d.RunUntilComplete();
+
+  ASSERT_EQ(1u, nel_service.errors().size());
+  EXPECT_EQ(kHeaderUserAgent, nel_service.errors()[0].user_agent);
+}
+
+TEST_F(URLRequestTestHTTP, NelReportUserAgentWithHeaderWithoutSettings) {
+  EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  ASSERT_TRUE(https_test_server.Start());
+  GURL request_url = https_test_server.base_url();
+
+  TestNetworkDelegate network_delegate;
+  TestNetworkErrorLoggingService nel_service;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_network_error_logging_service(&nel_service);
+  context.set_create_default_http_user_agent_settings(false);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->SetExtraRequestHeaderByName("User-Agent", kHeaderUserAgent, true);
+  request->Start();
+  d.RunUntilComplete();
+
+  ASSERT_EQ(1u, nel_service.errors().size());
+  EXPECT_EQ(kHeaderUserAgent, nel_service.errors()[0].user_agent);
+}
+
+TEST_F(URLRequestTestHTTP, NelReportUserAgentWithoutHeaderWithSettings) {
+  EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  ASSERT_TRUE(https_test_server.Start());
+  GURL request_url = https_test_server.base_url();
+
+  StaticHttpUserAgentSettings settings("en", kSettingsUserAgent);
+  TestNetworkDelegate network_delegate;
+  TestNetworkErrorLoggingService nel_service;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_network_error_logging_service(&nel_service);
+  context.set_http_user_agent_settings(&settings);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->Start();
+  d.RunUntilComplete();
+
+  ASSERT_EQ(1u, nel_service.errors().size());
+  EXPECT_EQ(kSettingsUserAgent, nel_service.errors()[0].user_agent);
+}
+
+TEST_F(URLRequestTestHTTP, NelReportUserAgentWithoutHeaderWithoutSettings) {
+  EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  ASSERT_TRUE(https_test_server.Start());
+  GURL request_url = https_test_server.base_url();
+
+  TestNetworkDelegate network_delegate;
+  TestNetworkErrorLoggingService nel_service;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_network_error_logging_service(&nel_service);
+  context.set_create_default_http_user_agent_settings(false);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->Start();
+  d.RunUntilComplete();
+
+  ASSERT_EQ(1u, nel_service.errors().size());
+  EXPECT_EQ("", nel_service.errors()[0].user_agent);
+}
+
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
 TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) {
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 3aaaab47..5d20147 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -1535,7 +1535,8 @@
       reporting_service.get());
 
   GURL domain("http://google.com");
-  reporting_service->QueueReport(domain, "group", "type", nullptr, 0);
+  reporting_service->QueueReport(domain, "Mozilla/1.0", "group", "type",
+                                 nullptr, 0);
 
   std::vector<const net::ReportingReport*> reports;
   reporting_cache->GetReports(&reports);
@@ -1564,9 +1565,11 @@
       reporting_service.get());
 
   GURL domain1("http://google.com");
-  reporting_service->QueueReport(domain1, "group", "type", nullptr, 0);
+  reporting_service->QueueReport(domain1, "Mozilla/1.0", "group", "type",
+                                 nullptr, 0);
   GURL domain2("http://chromium.org");
-  reporting_service->QueueReport(domain2, "group", "type", nullptr, 0);
+  reporting_service->QueueReport(domain2, "Mozilla/1.0", "group", "type",
+                                 nullptr, 0);
 
   std::vector<const net::ReportingReport*> reports;
   reporting_cache->GetReports(&reports);
@@ -1601,9 +1604,11 @@
       reporting_service.get());
 
   GURL domain1("http://192.168.0.1");
-  reporting_service->QueueReport(domain1, "group", "type", nullptr, 0);
+  reporting_service->QueueReport(domain1, "Mozilla/1.0", "group", "type",
+                                 nullptr, 0);
   GURL domain2("http://192.168.0.2");
-  reporting_service->QueueReport(domain2, "group", "type", nullptr, 0);
+  reporting_service->QueueReport(domain2, "Mozilla/1.0", "group", "type",
+                                 nullptr, 0);
 
   std::vector<const net::ReportingReport*> reports;
   reporting_cache->GetReports(&reports);