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