• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/metrics/net/net_metrics_log_uploader.h"
6 
7 #include <memory>
8 #include <string_view>
9 
10 #include "base/base64.h"
11 #include "base/functional/bind.h"
12 #include "base/run_loop.h"
13 #include "base/test/bind.h"
14 #include "base/test/task_environment.h"
15 #include "components/encrypted_messages/encrypted_message.pb.h"
16 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
17 #include "services/network/test/test_url_loader_factory.h"
18 #include "services/network/test/test_utils.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/metrics_proto/reporting_info.pb.h"
21 #include "third_party/zlib/google/compression_utils.h"
22 #include "url/gurl.h"
23 
24 namespace metrics {
25 
26 class NetMetricsLogUploaderTest : public testing::Test {
27  public:
NetMetricsLogUploaderTest()28   NetMetricsLogUploaderTest()
29       : on_upload_complete_count_(0),
30         test_shared_url_loader_factory_(
31             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
32                 &test_url_loader_factory_)) {
33     test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
34         [&](const network::ResourceRequest& request) {
35           upload_data_ = network::GetUploadData(request);
36           headers_ = request.headers;
37           loop_.Quit();
38         }));
39   }
40 
41   NetMetricsLogUploaderTest(const NetMetricsLogUploaderTest&) = delete;
42   NetMetricsLogUploaderTest& operator=(const NetMetricsLogUploaderTest&) =
43       delete;
44 
CreateAndOnUploadCompleteReuseUploader()45   void CreateAndOnUploadCompleteReuseUploader() {
46     ReportingInfo reporting_info;
47     reporting_info.set_attempt_count(10);
48     uploader_ = std::make_unique<NetMetricsLogUploader>(
49         test_shared_url_loader_factory_, GURL("https://dummy_server"),
50         "dummy_mime", MetricsLogUploader::UMA,
51         base::BindRepeating(
52             &NetMetricsLogUploaderTest::OnUploadCompleteReuseUploader,
53             base::Unretained(this)));
54     uploader_->UploadLog("initial_dummy_data", LogMetadata(),
55                          "initial_dummy_hash", "initial_dummy_signature",
56                          reporting_info);
57   }
58 
CreateUploaderAndUploadToSecureURL(const std::string & url)59   void CreateUploaderAndUploadToSecureURL(const std::string& url) {
60     ReportingInfo dummy_reporting_info;
61     uploader_ = std::make_unique<NetMetricsLogUploader>(
62         test_shared_url_loader_factory_, GURL(url), "dummy_mime",
63         MetricsLogUploader::UMA,
64         base::BindRepeating(&NetMetricsLogUploaderTest::DummyOnUploadComplete,
65                             base::Unretained(this)));
66     uploader_->UploadLog("dummy_data", LogMetadata(), "dummy_hash",
67                          "dummy_signature", dummy_reporting_info);
68   }
69 
CreateUploaderAndUploadToInsecureURL()70   void CreateUploaderAndUploadToInsecureURL() {
71     ReportingInfo dummy_reporting_info;
72     uploader_ = std::make_unique<NetMetricsLogUploader>(
73         test_shared_url_loader_factory_, GURL("http://dummy_insecure_server"),
74         "dummy_mime", MetricsLogUploader::UMA,
75         base::BindRepeating(&NetMetricsLogUploaderTest::DummyOnUploadComplete,
76                             base::Unretained(this)));
77     std::string compressed_message;
78     // Compress the data since the encryption code expects a compressed log,
79     // and tries to decompress it before encrypting it.
80     compression::GzipCompress(base::span_from_cstring("dummy_data"),
81                               &compressed_message);
82     uploader_->UploadLog(compressed_message, LogMetadata(), "dummy_hash",
83                          "dummy_signature", dummy_reporting_info);
84   }
85 
DummyOnUploadComplete(int response_code,int error_code,bool was_https,bool force_discard,std::string_view force_discard_reason)86   void DummyOnUploadComplete(int response_code,
87                              int error_code,
88                              bool was_https,
89                              bool force_discard,
90                              std::string_view force_discard_reason) {
91     log_was_force_discarded_ = force_discard;
92   }
93 
OnUploadCompleteReuseUploader(int response_code,int error_code,bool was_https,bool force_discard,std::string_view force_discard_reason)94   void OnUploadCompleteReuseUploader(int response_code,
95                                      int error_code,
96                                      bool was_https,
97                                      bool force_discard,
98                                      std::string_view force_discard_reason) {
99     ++on_upload_complete_count_;
100     if (on_upload_complete_count_ == 1) {
101       ReportingInfo reporting_info;
102       reporting_info.set_attempt_count(20);
103       uploader_->UploadLog("dummy_data", LogMetadata(), "dummy_hash",
104                            "dummy_signature", reporting_info);
105     }
106     log_was_force_discarded_ = force_discard;
107   }
108 
on_upload_complete_count() const109   int on_upload_complete_count() const {
110     return on_upload_complete_count_;
111   }
112 
test_url_loader_factory()113   network::TestURLLoaderFactory* test_url_loader_factory() {
114     return &test_url_loader_factory_;
115   }
116 
last_request_headers()117   const net::HttpRequestHeaders& last_request_headers() { return headers_; }
118 
last_upload_data()119   const std::string& last_upload_data() { return upload_data_; }
120 
WaitForRequest()121   void WaitForRequest() { loop_.Run(); }
122 
log_was_force_discarded()123   bool log_was_force_discarded() { return log_was_force_discarded_; }
124 
125  private:
126   std::unique_ptr<NetMetricsLogUploader> uploader_;
127   int on_upload_complete_count_;
128 
129   network::TestURLLoaderFactory test_url_loader_factory_;
130   scoped_refptr<network::SharedURLLoaderFactory>
131       test_shared_url_loader_factory_;
132 
133   base::test::TaskEnvironment task_environment_;
134 
135   base::RunLoop loop_;
136   std::string upload_data_;
137   net::HttpRequestHeaders headers_;
138   bool log_was_force_discarded_ = false;
139 };
140 
CheckReportingInfoHeader(net::HttpRequestHeaders headers,int expected_attempt_count)141 void CheckReportingInfoHeader(net::HttpRequestHeaders headers,
142                               int expected_attempt_count) {
143   std::string reporting_info_string;
144   EXPECT_TRUE(base::Base64Decode(
145       headers.GetHeader("X-Chrome-UMA-ReportingInfo").value(),
146       &reporting_info_string));
147   ReportingInfo reporting_info;
148   EXPECT_TRUE(reporting_info.ParseFromString(reporting_info_string));
149   EXPECT_EQ(reporting_info.attempt_count(), expected_attempt_count);
150 }
151 
TEST_F(NetMetricsLogUploaderTest,OnUploadCompleteReuseUploader)152 TEST_F(NetMetricsLogUploaderTest, OnUploadCompleteReuseUploader) {
153   CreateAndOnUploadCompleteReuseUploader();
154   WaitForRequest();
155 
156   // Mimic the initial fetcher callback.
157   CheckReportingInfoHeader(last_request_headers(), 10);
158   auto* pending_request_0 = test_url_loader_factory()->GetPendingRequest(0);
159   test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList(
160       pending_request_0, "");
161 
162   // Mimic the second fetcher callback.
163   CheckReportingInfoHeader(last_request_headers(), 20);
164   auto* pending_request_1 = test_url_loader_factory()->GetPendingRequest(1);
165   test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList(
166       pending_request_1, "");
167 
168   EXPECT_EQ(on_upload_complete_count(), 2);
169   EXPECT_FALSE(log_was_force_discarded());
170 }
171 
172 // Verifies that when no server URLs are specified, the logs are forcibly
173 // discarded.
TEST_F(NetMetricsLogUploaderTest,ForceDiscard)174 TEST_F(NetMetricsLogUploaderTest, ForceDiscard) {
175   CreateUploaderAndUploadToSecureURL(/*url=*/"");
176   WaitForRequest();
177 
178   // Mimic the initial fetcher callback.
179   auto* pending_request_0 = test_url_loader_factory()->GetPendingRequest(0);
180   test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList(
181       pending_request_0, "");
182 
183   EXPECT_TRUE(log_was_force_discarded());
184 }
185 
186 // Test that attempting to upload to an HTTP URL results in an encrypted
187 // message.
TEST_F(NetMetricsLogUploaderTest,MessageOverHTTPIsEncrypted)188 TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPIsEncrypted) {
189   CreateUploaderAndUploadToInsecureURL();
190   WaitForRequest();
191   encrypted_messages::EncryptedMessage message;
192   EXPECT_TRUE(message.ParseFromString(last_upload_data()));
193 }
194 
195 // Test that attempting to upload to an HTTPS URL results in an unencrypted
196 // message.
TEST_F(NetMetricsLogUploaderTest,MessageOverHTTPSIsNotEncrypted)197 TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPSIsNotEncrypted) {
198   CreateUploaderAndUploadToSecureURL("https://dummy_secure_server");
199   WaitForRequest();
200   EXPECT_EQ(last_upload_data(), "dummy_data");
201 }
202 
203 // Test that attempting to upload to localhost over http results in an
204 // unencrypted message.
TEST_F(NetMetricsLogUploaderTest,MessageOverHTTPLocalhostIsNotEncrypted)205 TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPLocalhostIsNotEncrypted) {
206   CreateUploaderAndUploadToSecureURL("http://localhost");
207   WaitForRequest();
208   EXPECT_EQ(last_upload_data(), "dummy_data");
209 }
210 
211 }  // namespace metrics
212