| // Copyright 2015 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 "components/metrics/net/net_metrics_log_uploader.h" |
| |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind_test_util.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "components/encrypted_messages/encrypted_message.pb.h" |
| #include "net/url_request/test_url_fetcher_factory.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "services/network/test/test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/metrics_proto/reporting_info.pb.h" |
| #include "third_party/zlib/google/compression_utils.h" |
| #include "url/gurl.h" |
| |
| namespace metrics { |
| |
| class NetMetricsLogUploaderTest : public testing::Test { |
| public: |
| NetMetricsLogUploaderTest() |
| : on_upload_complete_count_(0), |
| test_shared_url_loader_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory_)) { |
| test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( |
| [&](const network::ResourceRequest& request) { |
| upload_data_ = network::GetUploadData(request); |
| headers_ = request.headers; |
| loop_.Quit(); |
| })); |
| } |
| |
| void CreateAndOnUploadCompleteReuseUploader() { |
| ReportingInfo reporting_info; |
| reporting_info.set_attempt_count(10); |
| uploader_.reset(new NetMetricsLogUploader( |
| test_shared_url_loader_factory_, "https://dummy_server", "dummy_mime", |
| MetricsLogUploader::UMA, |
| base::Bind(&NetMetricsLogUploaderTest::OnUploadCompleteReuseUploader, |
| base::Unretained(this)))); |
| uploader_->UploadLog("initial_dummy_data", "initial_dummy_hash", |
| reporting_info); |
| } |
| |
| void CreateUploaderAndUploadToSecureURL(const std::string& url) { |
| ReportingInfo dummy_reporting_info; |
| uploader_.reset(new NetMetricsLogUploader( |
| test_shared_url_loader_factory_, url, "dummy_mime", |
| MetricsLogUploader::UMA, |
| base::Bind(&NetMetricsLogUploaderTest::DummyOnUploadComplete, |
| base::Unretained(this)))); |
| uploader_->UploadLog("dummy_data", "dummy_hash", dummy_reporting_info); |
| } |
| |
| void CreateUploaderAndUploadToInsecureURL() { |
| ReportingInfo dummy_reporting_info; |
| uploader_.reset(new NetMetricsLogUploader( |
| test_shared_url_loader_factory_, "http://dummy_insecure_server", |
| "dummy_mime", MetricsLogUploader::UMA, |
| base::Bind(&NetMetricsLogUploaderTest::DummyOnUploadComplete, |
| base::Unretained(this)))); |
| std::string compressed_message; |
| // Compress the data since the encryption code expects a compressed log, |
| // and tries to decompress it before encrypting it. |
| compression::GzipCompress("dummy_data", &compressed_message); |
| uploader_->UploadLog(compressed_message, "dummy_hash", |
| dummy_reporting_info); |
| } |
| |
| void DummyOnUploadComplete(int response_code, |
| int error_code, |
| bool was_https) {} |
| |
| void OnUploadCompleteReuseUploader(int response_code, |
| int error_code, |
| bool was_https) { |
| ++on_upload_complete_count_; |
| if (on_upload_complete_count_ == 1) { |
| ReportingInfo reporting_info; |
| reporting_info.set_attempt_count(20); |
| uploader_->UploadLog("dummy_data", "dummy_hash", reporting_info); |
| } |
| } |
| |
| network::TestURLLoaderFactory::PendingRequest* GetPendingRequest( |
| size_t index) { |
| if (index >= test_url_loader_factory_.pending_requests()->size()) |
| return nullptr; |
| auto* request = &(*test_url_loader_factory_.pending_requests())[index]; |
| DCHECK(request); |
| return request; |
| } |
| |
| int on_upload_complete_count() const { |
| return on_upload_complete_count_; |
| } |
| |
| network::TestURLLoaderFactory* test_url_loader_factory() { |
| return &test_url_loader_factory_; |
| } |
| |
| const net::HttpRequestHeaders& last_request_headers() { return headers_; } |
| |
| const std::string& last_upload_data() { return upload_data_; } |
| |
| void WaitForRequest() { loop_.Run(); } |
| |
| private: |
| std::unique_ptr<NetMetricsLogUploader> uploader_; |
| int on_upload_complete_count_; |
| |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> |
| test_shared_url_loader_factory_; |
| |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| |
| base::RunLoop loop_; |
| std::string upload_data_; |
| net::HttpRequestHeaders headers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NetMetricsLogUploaderTest); |
| }; |
| |
| void CheckReportingInfoHeader(net::HttpRequestHeaders headers, |
| int expected_attempt_count) { |
| std::string reporting_info_base64; |
| EXPECT_TRUE( |
| headers.GetHeader("X-Chrome-UMA-ReportingInfo", &reporting_info_base64)); |
| std::string reporting_info_string; |
| EXPECT_TRUE( |
| base::Base64Decode(reporting_info_base64, &reporting_info_string)); |
| ReportingInfo reporting_info; |
| EXPECT_TRUE(reporting_info.ParseFromString(reporting_info_string)); |
| EXPECT_EQ(reporting_info.attempt_count(), expected_attempt_count); |
| } |
| |
| TEST_F(NetMetricsLogUploaderTest, OnUploadCompleteReuseUploader) { |
| CreateAndOnUploadCompleteReuseUploader(); |
| WaitForRequest(); |
| |
| // Mimic the initial fetcher callback. |
| CheckReportingInfoHeader(last_request_headers(), 10); |
| test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList( |
| GetPendingRequest(0), ""); |
| |
| // Mimic the second fetcher callback. |
| CheckReportingInfoHeader(last_request_headers(), 20); |
| test_url_loader_factory()->SimulateResponseWithoutRemovingFromPendingList( |
| GetPendingRequest(1), ""); |
| |
| EXPECT_EQ(on_upload_complete_count(), 2); |
| } |
| |
| // Test that attempting to upload to an HTTP URL results in an encrypted |
| // message. |
| TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPIsEncrypted) { |
| CreateUploaderAndUploadToInsecureURL(); |
| WaitForRequest(); |
| encrypted_messages::EncryptedMessage message; |
| EXPECT_TRUE(message.ParseFromString(last_upload_data())); |
| } |
| |
| // Test that attempting to upload to an HTTPS URL results in an unencrypted |
| // message. |
| TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPSIsNotEncrypted) { |
| CreateUploaderAndUploadToSecureURL("https://dummy_secure_server"); |
| WaitForRequest(); |
| EXPECT_EQ(last_upload_data(), "dummy_data"); |
| } |
| |
| // Test that attempting to upload to localhost over http results in an |
| // unencrypted message. |
| TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPLocalhostIsNotEncrypted) { |
| CreateUploaderAndUploadToSecureURL("http://localhost"); |
| WaitForRequest(); |
| EXPECT_EQ(last_upload_data(), "dummy_data"); |
| } |
| |
| } // namespace metrics |