| // 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 "chrome/browser/page_load_metrics/observers/local_network_requests_page_load_metrics_observer.h" |
| |
| #include <vector> |
| |
| #include "base/test/metrics/histogram_tester.h" |
| #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h" |
| #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" |
| #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" |
| #include "chrome/browser/page_load_metrics/page_load_tracker.h" |
| #include "components/ukm/ukm_source.h" |
| #include "content/public/browser/global_request_id.h" |
| #include "content/public/common/resource_type.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/net_errors.h" |
| #include "services/metrics/public/cpp/ukm_builders.h" |
| #include "url/gurl.h" |
| |
| namespace internal { |
| |
| typedef struct { |
| char* url; |
| char* host_ip; |
| uint16_t port; |
| } PageAddressInfo; |
| |
| typedef struct { |
| internal::ResourceType resource_type; |
| internal::PortType port_type; |
| int success_count, failed_count; |
| } UkmMetricInfo; |
| |
| static const PageAddressInfo |
| kPublicPage = {(char*)"https://foo.com/", (char*)"216.58.195.78", 443}, |
| kPublicPageIPv6 = {(char*)"https://google.com/", |
| (char*)"[2607:f8b0:4005:809::200e]", 443}, |
| kPrivatePage = {(char*)"http://test.local/", (char*)"192.168.10.123", 80}, |
| kLocalhostPage = {(char*)"http://localhost/", (char*)"127.0.0.1", 80}, |
| kLocalhostPageIPv6 = {(char*)"http://[::1]/", (char*)"[::1]", 80}, |
| kPublicRequest1 = {(char*)"http://bar.com/", (char*)"100.150.200.250", 80}, |
| kPublicRequest2 = {(char*)"https://www.baz.com/", (char*)"192.10.20.30", |
| 443}, |
| kSameSubnetRequest1 = {(char*)"http://test2.local:9000/", |
| (char*)"192.168.10.200", 9000}, |
| kSameSubnetRequest2 = {(char*)"http://test2.local:8000/index.html", |
| (char*)"192.168.10.200", 8000}, |
| kSameSubnetRequest3 = {(char*)"http://test2.local:8000/bar.html", |
| (char*)"192.168.10.200", 8000}, |
| kDiffSubnetRequest1 = {(char*)"http://10.0.10.200/", (char*)"10.0.10.200", |
| 80}, |
| kDiffSubnetRequest2 = {(char*)"http://172.16.0.85:8181/", |
| (char*)"172.16.0.85", 8181}, |
| kDiffSubnetRequest3 = {(char*)"http://10.15.20.25:12345/", |
| (char*)"10.15.20.25", 12345}, |
| kDiffSubnetRequest4 = {(char*)"http://172.31.100.20:515/", |
| (char*)"172.31.100.20", 515}, |
| kLocalhostRequest1 = {(char*)"http://localhost:8080/", (char*)"127.0.0.1", |
| 8080}, // WEB |
| kLocalhostRequest2 = {(char*)"http://127.0.1.1:3306/", (char*)"127.0.1.1", |
| 3306}, // DB |
| kLocalhostRequest3 = {(char*)"http://localhost:515/", (char*)"127.0.2.1", |
| 515}, // PRINT |
| kLocalhostRequest4 = {(char*)"http://127.100.150.200:9000/", |
| (char*)"127.100.150.200", 9000}, // DEV |
| kLocalhostRequest5 = {(char*)"http://127.0.0.1:9876/", (char*)"127.0.0.1", |
| 9876}, // OTHER |
| kRouterRequest1 = {(char*)"http://10.0.0.1/", (char*)"10.0.0.1", 80}, |
| kRouterRequest2 = {(char*)"https://192.168.10.1/", (char*)"192.168.10.1", |
| 443}; |
| |
| } // namespace internal |
| |
| class LocalNetworkRequestsPageLoadMetricsObserverTest |
| : public page_load_metrics::PageLoadMetricsObserverTestHarness { |
| protected: |
| void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override { |
| tracker->AddObserver( |
| std::make_unique<LocalNetworkRequestsPageLoadMetricsObserver>()); |
| } |
| |
| void SetUp() override { |
| page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp(); |
| } |
| |
| void SimulateNavigateAndCommit(const internal::PageAddressInfo& page) { |
| GURL url(page.url); |
| net::HostPortPair socket_address(page.host_ip, page.port); |
| |
| navigation_simulator_ = |
| content::NavigationSimulator::CreateRendererInitiated(url, main_rfh()); |
| navigation_simulator_->Start(); |
| navigation_simulator_->SetSocketAddress(socket_address); |
| navigation_simulator_->Commit(); |
| } |
| |
| void SimulateLoadedSuccessfulResource( |
| const internal::PageAddressInfo& resource) { |
| SimulateLoadedResource(resource, 0); |
| } |
| |
| void SimulateLoadedFailedResource(const internal::PageAddressInfo& resource) { |
| SimulateLoadedResource(resource, net::ERR_CONNECTION_REFUSED); |
| } |
| |
| void SimulateLoadedResource(const internal::PageAddressInfo& resource, |
| const int net_error) { |
| page_load_metrics::ExtraRequestCompleteInfo request_info( |
| GURL(resource.url), net::HostPortPair(resource.host_ip, resource.port), |
| -1 /* frame_tree_node_id */, !net_error /* was_cached */, |
| (net_error ? 1024 * 20 : 0) /* raw_body_bytes */, |
| 0 /* original_network_content_length */, |
| nullptr /* data_reduction_proxy_data */, |
| content::ResourceType::RESOURCE_TYPE_MAIN_FRAME, net_error, |
| {} /* load_timing_info */); |
| |
| PageLoadMetricsObserverTestHarness::SimulateLoadedResource( |
| request_info, navigation_simulator_->GetGlobalRequestID()); |
| } |
| |
| void NavigateToPageAndLoadResources( |
| const internal::PageAddressInfo& page, |
| const std::vector<std::pair<internal::PageAddressInfo, bool>>& |
| resources_and_statuses) { |
| SimulateNavigateAndCommit(page); |
| for (size_t i = 0; i < resources_and_statuses.size(); ++i) { |
| if (resources_and_statuses[i].second) { |
| SimulateLoadedSuccessfulResource(resources_and_statuses[i].first); |
| } else { |
| SimulateLoadedFailedResource(resources_and_statuses[i].first); |
| } |
| } |
| DeleteContents(); |
| } |
| |
| const content::GlobalRequestID GetGlobalRequestID() { |
| DCHECK(navigation_simulator_); |
| return navigation_simulator_->GetGlobalRequestID(); |
| } |
| |
| // Helper functions to verify that particular slices of UMA histograms are |
| // empty. |
| void ExpectEmptyHistograms(internal::DomainType domain_type) { |
| for (const auto& port : |
| internal::GetLocalhostHistogramNames().at(domain_type)) { |
| for (const auto& histogramName : port.second) { |
| histogram_tester().ExpectUniqueSample(histogramName.second, 0, 1); |
| } |
| } |
| for (const auto& resource : |
| internal::GetNonlocalhostHistogramNames().at(domain_type)) { |
| for (const auto& histogramName : resource.second) { |
| histogram_tester().ExpectUniqueSample(histogramName.second, 0, 1); |
| } |
| } |
| } |
| |
| void ExpectNoHistograms() { |
| for (const auto& domain : internal::GetLocalhostHistogramNames()) { |
| for (const auto& port : domain.second) { |
| for (const auto& status : port.second) { |
| histogram_tester().ExpectTotalCount(status.second, 0); |
| } |
| } |
| } |
| for (const auto& domain : internal::GetNonlocalhostHistogramNames()) { |
| for (const auto& resource : domain.second) { |
| for (const auto& status : resource.second) { |
| histogram_tester().ExpectTotalCount(status.second, 0); |
| } |
| } |
| } |
| } |
| |
| void ExpectUkmPageDomainMetric(const internal::PageAddressInfo& page, |
| const internal::DomainType domain_type) { |
| auto entries = test_ukm_recorder().GetEntriesByName( |
| ukm::builders::PageDomainInfo::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| for (const auto* const entry : entries) { |
| test_ukm_recorder().ExpectEntrySourceHasUrl(entry, GURL(page.url)); |
| test_ukm_recorder().ExpectEntryMetric( |
| entry, ukm::builders::PageDomainInfo::kDomainTypeName, |
| static_cast<int>(domain_type)); |
| } |
| } |
| |
| void ExpectMetricsAndHistograms( |
| const internal::PageAddressInfo& page, |
| const std::vector<internal::UkmMetricInfo>& expected_metrics, |
| const std::map<std::string, int>& expected_histograms) { |
| using LocalNetworkRequests = ukm::builders::LocalNetworkRequests; |
| auto entries = |
| test_ukm_recorder().GetEntriesByName(LocalNetworkRequests::kEntryName); |
| ASSERT_EQ(entries.size(), expected_metrics.size()); |
| for (size_t i = 0; i < entries.size() && i < expected_metrics.size(); i++) { |
| test_ukm_recorder().ExpectEntrySourceHasUrl(entries[i], GURL(page.url)); |
| test_ukm_recorder().ExpectEntryMetric( |
| entries[i], LocalNetworkRequests::kResourceTypeName, |
| expected_metrics[i].resource_type); |
| test_ukm_recorder().ExpectEntryMetric( |
| entries[i], LocalNetworkRequests::kCount_SuccessfulName, |
| expected_metrics[i].success_count); |
| test_ukm_recorder().ExpectEntryMetric( |
| entries[i], LocalNetworkRequests::kCount_FailedName, |
| expected_metrics[i].failed_count); |
| if (expected_metrics[i].resource_type == |
| internal::RESOURCE_TYPE_LOCALHOST) { |
| test_ukm_recorder().ExpectEntryMetric( |
| entries[i], LocalNetworkRequests::kPortTypeName, |
| static_cast<int>(expected_metrics[i].port_type)); |
| } |
| } |
| |
| // Should have generated UMA histograms for all requests made. |
| for (auto hist : expected_histograms) { |
| histogram_tester().ExpectUniqueSample(hist.first, hist.second, 1); |
| } |
| } |
| |
| private: |
| std::unique_ptr<content::NavigationSimulator> navigation_simulator_; |
| }; |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, NoMetrics) { |
| EXPECT_EQ(0ul, test_ukm_recorder().sources_count()); |
| EXPECT_EQ(0ul, test_ukm_recorder().entries_count()); |
| |
| // Sanity check |
| ExpectNoHistograms(); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPageIPv6PublicRequests) { |
| // Navigate to a public page and make only public resource requests. |
| const internal::PageAddressInfo& page = internal::kPublicPageIPv6; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicRequest1, true}, |
| {internal::kPublicPageIPv6, true}}); |
| |
| // Should generate only a domain type UKM entry and nothing else. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| ExpectEmptyHistograms(internal::DOMAIN_TYPE_PUBLIC); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPagePublicRequests) { |
| // Navigate to a public page and make only public resource requests. |
| const internal::PageAddressInfo& page = internal::kPublicPage; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicRequest1, true}, |
| {internal::kPublicRequest2, true}, |
| {internal::kPublicPageIPv6, true}}); |
| |
| // Should generate only a domain type UKM entry and nothing else. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| ExpectEmptyHistograms(internal::DOMAIN_TYPE_PUBLIC); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PrivatePageSelfRequests) { |
| // Navigate to a private page and make resource requests only to the page |
| // itself. |
| const internal::PageAddressInfo& page = internal::kSameSubnetRequest1; |
| NavigateToPageAndLoadResources(page, {{internal::kSameSubnetRequest2, true}, |
| {internal::kSameSubnetRequest3, false}, |
| {page, true}}); |
| |
| // Should generate only a domain type UKM entry and nothing else. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PRIVATE); |
| ExpectEmptyHistograms(internal::DOMAIN_TYPE_PRIVATE); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, PrivatePageNoRequests) { |
| // Navigate to a private page and make no resource requests. |
| const internal::PageAddressInfo& page = internal::kPrivatePage; |
| NavigateToPageAndLoadResources( |
| page, std::vector<std::pair<internal::PageAddressInfo, bool>>{}); |
| |
| // Should generate only a domain type UKM entry and nothing else. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PRIVATE); |
| ExpectEmptyHistograms(internal::DOMAIN_TYPE_PRIVATE); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, LocalhostPage) { |
| // Navigate to a localhost page and make some arbitrary resource requests. |
| const internal::PageAddressInfo& page = internal::kLocalhostPage; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicRequest1, true}, |
| {internal::kPublicRequest2, false}, |
| {internal::kSameSubnetRequest1, true}, |
| {internal::kLocalhostRequest5, true}}); |
| |
| // Should generate only a domain type UKM entry and nothing else. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_LOCALHOST); |
| ExpectNoHistograms(); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, LocalhostPageIPv6) { |
| // Navigate to a localhost page with an IPv6 address and make some arbitrary |
| // resource requests. |
| const internal::PageAddressInfo& page = internal::kLocalhostPageIPv6; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicRequest1, false}, |
| {internal::kLocalhostRequest2, true}, |
| {internal::kDiffSubnetRequest1, false}, |
| {internal::kLocalhostRequest4, true}}); |
| |
| // Should generate only a domain type UKM entry and nothing else. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_LOCALHOST); |
| ExpectNoHistograms(); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPageAllSuccessfulRequests) { |
| // Navigate to a public page and make successful resource requests to all |
| // resource types. |
| const internal::PageAddressInfo& page = internal::kPublicPage; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicPage, true}, |
| {internal::kPublicPageIPv6, true}, |
| {internal::kPrivatePage, true}, |
| {internal::kLocalhostPage, true}, |
| {internal::kLocalhostPageIPv6, true}, |
| {internal::kPublicRequest1, true}, |
| {internal::kPublicRequest2, true}, |
| {internal::kSameSubnetRequest1, true}, |
| {internal::kSameSubnetRequest2, true}, |
| {internal::kSameSubnetRequest3, true}, |
| {internal::kDiffSubnetRequest1, true}, |
| {internal::kDiffSubnetRequest2, true}, |
| {internal::kLocalhostRequest1, true}, |
| {internal::kLocalhostRequest2, true}, |
| {internal::kLocalhostRequest3, true}, |
| {internal::kLocalhostRequest4, true}, |
| {internal::kLocalhostRequest5, true}, |
| {internal::kRouterRequest1, true}, |
| {internal::kRouterRequest2, true}}); |
| |
| // Should now have generated UKM entries for each of the types of resources |
| // requested except for the public resources. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| |
| // We should now see UKM entries and UMA histograms for each of the types of |
| // resources requested except for public resources. |
| ExpectMetricsAndHistograms( |
| page, |
| // List of expected UKM metric values. |
| { |
| {internal::RESOURCE_TYPE_ROUTER, internal::PORT_TYPE_WEB, 1, |
| 0}, // 10.0.0.1:80 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 1, |
| 0}, // 10.0.10.200:80 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 1, |
| 0}, // 172.16.0.85:8181 |
| {internal::RESOURCE_TYPE_ROUTER, internal::PORT_TYPE_WEB, 1, |
| 0}, // 192.168.10.1:443 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 1, |
| 0}, // 192.168.10.123:80 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 3, |
| 0}, // 192.168.10.200:8000 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 2, |
| 0}, // 127.0.0.1:80 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_PRINT, 1, |
| 0}, // 127.0.2.1:515 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DB, 1, |
| 0}, // 127.0.1.1:3306 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 1, |
| 0}, // 127.0.0.1:8080 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DEV, 1, |
| 0}, // 127.100.150.200:9000 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_OTHER, 1, |
| 0}, // 127.0.0.1:9876 |
| }, |
| // List of expected nonzero UMA histogram values. |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_ROUTER) |
| .at(true), |
| 2}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_PRIVATE) |
| .at(true), |
| 6}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_WEB) |
| .at(true), |
| 3}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_PRINT) |
| .at(true), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_DB) |
| .at(true), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_DEV) |
| .at(true), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_OTHER) |
| .at(true), |
| 1}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PrivatePageAllSuccessfulRequests) { |
| // Navigate to a private page and make successful resource requests to all |
| // resource types. |
| const internal::PageAddressInfo& page = internal::kPrivatePage; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicPage, true}, |
| {internal::kPublicPageIPv6, true}, |
| {internal::kPrivatePage, true}, |
| {internal::kLocalhostPage, true}, |
| {internal::kLocalhostPageIPv6, true}, |
| {internal::kPublicRequest1, true}, |
| {internal::kPublicRequest2, true}, |
| {internal::kSameSubnetRequest1, true}, |
| {internal::kSameSubnetRequest2, true}, |
| {internal::kSameSubnetRequest3, true}, |
| {internal::kDiffSubnetRequest1, true}, |
| {internal::kDiffSubnetRequest2, true}, |
| {internal::kLocalhostRequest1, true}, |
| {internal::kLocalhostRequest2, true}, |
| {internal::kLocalhostRequest3, true}, |
| {internal::kLocalhostRequest4, true}, |
| {internal::kLocalhostRequest5, true}, |
| {internal::kRouterRequest1, true}, |
| {internal::kRouterRequest2, true}}); |
| |
| // Should now have generated UKM entries for each of the types of resources |
| // requested except for the public resources. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PRIVATE); |
| |
| // We should now see UKM entries and UMA histograms for each of the types of |
| // resources requested except for the request to the page itself. |
| ExpectMetricsAndHistograms( |
| page, |
| // List of expected UKM metric values. |
| { |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 1, 0}, // 10.0.0.1:80 |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 1, 0}, // 10.0.10.200:80 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 1, |
| 0}, // 100.150.200.250:80 |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 1, 0}, // 172.16.0.85:8181 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 1, |
| 0}, // 192.10.20.30:443 |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_WEB, |
| 1, 0}, // 192.168.10.1:443 |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_WEB, |
| 3, 0}, // 192.168.10.200:8000 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 1, |
| 0}, // 216.58.195.78:443 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 1, |
| 0}, // [2607:f8b0:4005:809::200e]:443 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 2, |
| 0}, // 127.0.0.1:80 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_PRINT, 1, |
| 0}, // 127.0.2.1:515 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DB, 1, |
| 0}, // 127.0.1.1:3306 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 1, |
| 0}, // 127.0.0.1:8080 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DEV, 1, |
| 0}, // 127.100.150.200:9000 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_OTHER, 1, |
| 0}, // 127.0.0.1:9876 |
| }, |
| // List of expected nonzero UMA histogram values. |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_PUBLIC) |
| .at(true), |
| 4}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET) |
| .at(true), |
| 3}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET) |
| .at(true), |
| 4}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_WEB) |
| .at(true), |
| 3}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_PRINT) |
| .at(true), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_DB) |
| .at(true), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_DEV) |
| .at(true), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_OTHER) |
| .at(true), |
| 1}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PrivatePageAllFailedRequests) { |
| // Navigate to a private page and make successful resource requests to all |
| // resource types. |
| const internal::PageAddressInfo& page = internal::kPrivatePage; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicPage, false}, |
| {internal::kPublicPageIPv6, false}, |
| {internal::kPrivatePage, false}, |
| {internal::kLocalhostPage, false}, |
| {internal::kLocalhostPageIPv6, false}, |
| {internal::kPublicRequest1, false}, |
| {internal::kPublicRequest2, false}, |
| {internal::kSameSubnetRequest1, false}, |
| {internal::kSameSubnetRequest2, false}, |
| {internal::kSameSubnetRequest3, false}, |
| {internal::kDiffSubnetRequest1, false}, |
| {internal::kDiffSubnetRequest2, false}, |
| {internal::kLocalhostRequest1, false}, |
| {internal::kLocalhostRequest2, false}, |
| {internal::kLocalhostRequest3, false}, |
| {internal::kLocalhostRequest4, false}, |
| {internal::kLocalhostRequest5, false}, |
| {internal::kRouterRequest1, false}, |
| {internal::kRouterRequest2, false}}); |
| |
| // Should now have generated UKM entries for each of the types of resources |
| // requested except for the public resources. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PRIVATE); |
| |
| ExpectMetricsAndHistograms( |
| page, |
| // List of expected UKM metric values. |
| { |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 10.0.0.1:80 |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 10.0.10.200:80 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 0, |
| 1}, // 100.150.200.250:80 |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 172.16.0.85:8181 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 0, |
| 1}, // 192.10.20.30:443 |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 192.168.10.1:443 |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 3}, // 192.168.10.200:8000 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 0, |
| 1}, // 216.58.195.78:443 |
| {internal::RESOURCE_TYPE_PUBLIC, internal::PORT_TYPE_WEB, 0, |
| 1}, // [2607:f8b0:4005:809::200e]:443 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 0, |
| 2}, // 127.0.0.1:80 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_PRINT, 0, |
| 1}, // 127.0.2.1:515 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DB, 0, |
| 1}, // 127.0.1.1:3306 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 0, |
| 1}, // 127.0.0.1:8080 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DEV, 0, |
| 1}, // 127.100.150.200:9000 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_OTHER, 0, |
| 1}, // 127.0.0.1:9876 |
| }, |
| // List of expected nonzero UMA histogram values. |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_PUBLIC) |
| .at(false), |
| 4}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET) |
| .at(false), |
| 3}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET) |
| .at(false), |
| 4}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_WEB) |
| .at(false), |
| 3}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_PRINT) |
| .at(false), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_DB) |
| .at(false), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_DEV) |
| .at(false), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::PORT_TYPE_OTHER) |
| .at(false), |
| 1}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPageMixedStatusRequests) { |
| // Navigate to a public page and make mixed status resource requests. |
| const internal::PageAddressInfo& page = internal::kPublicPage; |
| NavigateToPageAndLoadResources(page, {{internal::kPublicRequest1, true}, |
| {internal::kSameSubnetRequest1, true}, |
| {internal::kLocalhostRequest2, false}, |
| {internal::kDiffSubnetRequest2, true}, |
| {internal::kLocalhostRequest5, false}, |
| {internal::kDiffSubnetRequest2, false}, |
| {internal::kRouterRequest1, true}}); |
| |
| // Should now have generated UKM entries for each of the types of resources |
| // requested except for the public resources. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| |
| ExpectMetricsAndHistograms( |
| page, |
| // List of expected UKM metric values. |
| { |
| {internal::RESOURCE_TYPE_ROUTER, internal::PORT_TYPE_WEB, 1, |
| 0}, // 10.0.0.1:80 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 1, |
| 1}, // 172.16.0.85:8181 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_DEV, 1, |
| 0}, // 192.168.10.200:8000 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_DB, 0, |
| 1}, // 127.0.1.1:3306 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_OTHER, 0, |
| 1}, // 127.0.0.1:9876 |
| }, |
| // List of expected nonzero UMA histogram values. |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_ROUTER) |
| .at(true), |
| 1}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_PRIVATE) |
| .at(true), |
| 2}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_PRIVATE) |
| .at(false), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_DB) |
| .at(false), |
| 1}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_OTHER) |
| .at(false), |
| 1}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPageLargeNumberOfRequests) { |
| // This test also verifies the sequence and timing of UKM metric generation. |
| |
| // Navigate to a public page with an IPv6 address. |
| const internal::PageAddressInfo& page = internal::kPublicPageIPv6; |
| SimulateNavigateAndCommit(page); |
| |
| // Should generate only a domain type UKM entry by this point. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| |
| // Make 100 each of many different types of requests, with 1000 of a single |
| // type. |
| std::vector<std::pair<internal::PageAddressInfo, bool>> requests = { |
| {internal::kPublicRequest1, true}, |
| {internal::kLocalhostPage, true}, |
| {internal::kLocalhostPageIPv6, false}, |
| {internal::kSameSubnetRequest1, false}, |
| {internal::kDiffSubnetRequest2, false}, |
| }; |
| for (auto request : requests) { |
| for (int i = 0; i < 100; ++i) { |
| SimulateLoadedResource(request.first, (request.second ? 0 : -1)); |
| } |
| } |
| for (int i = 0; i < 1000; ++i) { |
| SimulateLoadedSuccessfulResource(internal::kDiffSubnetRequest1); |
| } |
| |
| // At this point, we should still only see the domain type UKM entry. |
| EXPECT_EQ(1ul, test_ukm_recorder().entries_count()); |
| |
| // Close the page. |
| DeleteContents(); |
| |
| ExpectMetricsAndHistograms( |
| page, |
| // List of expected UKM metric values. |
| { |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 1000, |
| 0}, // 10.0.10.200:80 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 0, |
| 100}, // 172.16.0.85:8181 |
| {internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_DEV, 0, |
| 100}, // 192.168.10.200:9000 |
| {internal::RESOURCE_TYPE_LOCALHOST, internal::PORT_TYPE_WEB, 100, |
| 100}, // 127.0.0.1:80 |
| }, |
| // List of expected nonzero UMA histogram values. |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_PRIVATE) |
| .at(true), |
| 1000}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_PRIVATE) |
| .at(false), |
| 200}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_WEB) |
| .at(true), |
| 100}, |
| {internal::GetLocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::PORT_TYPE_WEB) |
| .at(false), |
| 100}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPageRequestIpInUrlOnly) { |
| const internal::PageAddressInfo& page = internal::kPublicPage; |
| SimulateNavigateAndCommit(page); |
| |
| // Load a resource that has the IP address in the URL but returned an empty |
| // socket address for some reason. |
| PageLoadMetricsObserverTestHarness::SimulateLoadedResource( |
| {GURL(internal::kDiffSubnetRequest2.url), net::HostPortPair(), |
| -1 /* frame_tree_node_id */, true /* was_cached */, |
| 1024 * 20 /* raw_body_bytes */, 0 /* original_network_content_length */, |
| nullptr /* data_reduction_proxy_data */, |
| content::ResourceType::RESOURCE_TYPE_MAIN_FRAME, 0, |
| nullptr /* load_timing_info */}, |
| GetGlobalRequestID()); |
| DeleteContents(); |
| |
| // We should still see a UKM entry and UMA histogram for the resource request. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| ExpectMetricsAndHistograms( |
| page, {{internal::RESOURCE_TYPE_PRIVATE, internal::PORT_TYPE_WEB, 1, 0}}, |
| {{internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PUBLIC) |
| .at(internal::RESOURCE_TYPE_PRIVATE) |
| .at(true), |
| 1}}); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, |
| PublicPageRequestIpNotPresent) { |
| const internal::PageAddressInfo& page = internal::kPublicPage; |
| SimulateNavigateAndCommit(page); |
| |
| // Load a resource that doesn't have the IP address in the URL and returned an |
| // empty socket address (e.g., failed DNS resolution). |
| PageLoadMetricsObserverTestHarness::SimulateLoadedResource( |
| {GURL(internal::kPrivatePage.url), net::HostPortPair(), |
| -1 /* frame_tree_node_id */, false /* was_cached */, |
| 0 /* raw_body_bytes */, 0 /* original_network_content_length */, |
| nullptr /* data_reduction_proxy_data */, |
| content::ResourceType::RESOURCE_TYPE_MAIN_FRAME, -20, |
| nullptr /* load_timing_info */}, |
| GetGlobalRequestID()); |
| DeleteContents(); |
| |
| // We shouldn't see any UKM entries or UMA histograms this time. |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PUBLIC); |
| ExpectEmptyHistograms(internal::DOMAIN_TYPE_PUBLIC); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, PrivatePageSubnet10) { |
| // Navigate to a private page on the 10.0.0.0/8 subnet and make requests to |
| // other 10.0.0.0/8 subnet resources. |
| const internal::PageAddressInfo& page = internal::kRouterRequest1; |
| NavigateToPageAndLoadResources(page, {{internal::kDiffSubnetRequest1, false}, |
| {internal::kDiffSubnetRequest3, false}, |
| {internal::kRouterRequest2, false}}); |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PRIVATE); |
| |
| // The first two requests should be on the same subnet and the last request |
| // should be on a different subnet. |
| ExpectMetricsAndHistograms( |
| page, |
| { |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 10.0.10.200:80 |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_OTHER, |
| 0, 1}, // 10.15.20.25:12345 |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 192.168.10.1:443 |
| }, |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET) |
| .at(false), |
| 2}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET) |
| .at(false), |
| 1}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, PrivatePageSubnet172) { |
| // Navigate to a private page on the 10.0.0.0/8 subnet and make requests to |
| // other 10.0.0.0/8 subnet resources. |
| const internal::PageAddressInfo& page = internal::kDiffSubnetRequest2; |
| NavigateToPageAndLoadResources(page, {{internal::kDiffSubnetRequest4, false}, |
| {internal::kRouterRequest1, false}}); |
| ExpectUkmPageDomainMetric(page, internal::DOMAIN_TYPE_PRIVATE); |
| |
| // The first two requests should be on the same subnet and the last request |
| // should be on a different subnet. |
| ExpectMetricsAndHistograms( |
| page, |
| { |
| {internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET, internal::PORT_TYPE_WEB, |
| 0, 1}, // 10.0.10.200:80 |
| {internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET, internal::PORT_TYPE_PRINT, |
| 0, 1}, // 172.31.100.20:515 |
| }, |
| { |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_SAME_SUBNET) |
| .at(false), |
| 1}, |
| {internal::GetNonlocalhostHistogramNames() |
| .at(internal::DOMAIN_TYPE_PRIVATE) |
| .at(internal::RESOURCE_TYPE_LOCAL_DIFF_SUBNET) |
| .at(false), |
| 1}, |
| }); |
| } |
| |
| TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, PrivatePageFailedLoad) { |
| GURL url(internal::kPrivatePage.url); |
| auto navigation_simulator = |
| content::NavigationSimulator::CreateRendererInitiated(url, main_rfh()); |
| navigation_simulator->Start(); |
| navigation_simulator->Fail(-20); |
| navigation_simulator->CommitErrorPage(); |
| |
| // Nothing should have been generated. |
| EXPECT_EQ(0ul, test_ukm_recorder().entries_count()); |
| ExpectNoHistograms(); |
| } |