blob: 395fb0722441fe3c96bf2fdda85a714fa7482613 [file] [log] [blame]
// Copyright 2018 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/renderer/page_load_metrics/page_resource_data_use.h"
#include "base/stl_util.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "third_party/blink/public/platform/web_url.h"
#include "url/gurl.h"
namespace page_load_metrics {
namespace {
// Returns true when the image is a placeholder for lazy load.
bool IsPartialImageRequest(content::ResourceType resource_type,
content::PreviewsState previews_state) {
if (resource_type != content::ResourceType::kImage)
return false;
return previews_state & content::PreviewsTypes::LAZY_IMAGE_LOAD_DEFERRED;
}
// Returns true if this resource was previously fetched as a placeholder.
bool IsImageAutoReload(content::ResourceType resource_type,
content::PreviewsState previews_state) {
if (resource_type != content::ResourceType::kImage)
return false;
return previews_state & content::PreviewsTypes::LAZY_IMAGE_AUTO_RELOAD;
}
// Returns the ratio of original data size (without applying interventions) to
// actual data use for a placeholder.
double EstimatePartialImageRequestSavings(
const network::ResourceResponseHead& response_head) {
if (!response_head.headers)
return 1.0;
if (response_head.headers->GetContentLength() <= 0)
return 1.0;
int64_t first, last, original_length;
if (!response_head.headers->GetContentRangeFor206(&first, &last,
&original_length)) {
return 1.0;
}
if (original_length < response_head.headers->GetContentLength())
return 1.0;
return original_length / response_head.headers->GetContentLength();
}
// Returns a ratio of original data use to actual data use while factoring in
// that this request was previously fetched as a placeholder, and therefore
// recorded savings earlier.
double EstimateAutoReloadImageRequestSavings(
const network::ResourceResponseHead& response_head) {
static const double kPlageholderContentInCache = 2048;
// Count the new network usage. For a reloaded placeholder image, 2KB will be
// in cache.
return kPlageholderContentInCache / response_head.headers->GetContentLength();
}
} // namespace
PageResourceDataUse::PageResourceDataUse()
: resource_id_(-1),
data_reduction_proxy_compression_ratio_estimate_(1.0),
total_received_bytes_(0),
last_update_bytes_(0),
is_complete_(false),
is_canceled_(false),
reported_as_ad_resource_(false),
is_main_frame_resource_(false),
is_secure_scheme_(false),
proxy_used_(false),
cache_type_(mojom::CacheType::kNotCached) {}
PageResourceDataUse::PageResourceDataUse(const PageResourceDataUse& other) =
default;
PageResourceDataUse::~PageResourceDataUse() = default;
void PageResourceDataUse::DidStartResponse(
const GURL& response_url,
int resource_id,
const network::ResourceResponseHead& response_head,
content::ResourceType resource_type,
content::PreviewsState previews_state) {
resource_id_ = resource_id;
if (IsPartialImageRequest(resource_type, previews_state)) {
data_reduction_proxy_compression_ratio_estimate_ =
EstimatePartialImageRequestSavings(response_head);
} else if (IsImageAutoReload(resource_type, previews_state)) {
data_reduction_proxy_compression_ratio_estimate_ =
EstimateAutoReloadImageRequestSavings(response_head);
} else {
data_reduction_proxy_compression_ratio_estimate_ =
data_reduction_proxy::EstimateCompressionRatioFromHeaders(
&response_head);
}
proxy_used_ = !response_head.proxy_server.is_direct();
mime_type_ = response_head.mime_type;
if (response_head.was_fetched_via_cache)
cache_type_ = mojom::CacheType::kHttp;
is_secure_scheme_ = response_url.SchemeIsCryptographic();
is_primary_frame_resource_ =
resource_type == content::ResourceType::kMainFrame ||
resource_type == content::ResourceType::kSubFrame;
origin_ = url::Origin::Create(response_url);
}
void PageResourceDataUse::DidReceiveTransferSizeUpdate(
int received_data_length) {
total_received_bytes_ += received_data_length;
}
void PageResourceDataUse::DidCompleteResponse(
const network::URLLoaderCompletionStatus& status) {
// Report the difference in received bytes.
is_complete_ = true;
encoded_body_length_ = status.encoded_body_length;
int64_t delta_bytes = status.encoded_data_length - total_received_bytes_;
if (delta_bytes > 0) {
total_received_bytes_ += delta_bytes;
}
}
void PageResourceDataUse::DidCancelResponse() {
is_canceled_ = true;
}
void PageResourceDataUse::DidLoadFromMemoryCache(const GURL& response_url,
int request_id,
int64_t encoded_body_length,
const std::string& mime_type) {
origin_ = url::Origin::Create(response_url);
resource_id_ = request_id;
mime_type_ = mime_type;
is_secure_scheme_ = response_url.SchemeIsCryptographic();
cache_type_ = mojom::CacheType::kMemory;
// Resources from the memory cache cannot be a primary frame resource.
is_primary_frame_resource_ = false;
is_complete_ = true;
encoded_body_length_ = encoded_body_length;
}
bool PageResourceDataUse::IsFinishedLoading() {
return is_complete_ || is_canceled_;
}
void PageResourceDataUse::SetReportedAsAdResource(
bool reported_as_ad_resource) {
reported_as_ad_resource_ = reported_as_ad_resource;
}
void PageResourceDataUse::SetIsMainFrameResource(bool is_main_frame_resource) {
is_main_frame_resource_ = is_main_frame_resource;
}
int PageResourceDataUse::CalculateNewlyReceivedBytes() {
int newly_received_bytes = total_received_bytes_ - last_update_bytes_;
last_update_bytes_ = total_received_bytes_;
DCHECK_GE(newly_received_bytes, 0);
return newly_received_bytes;
}
mojom::ResourceDataUpdatePtr PageResourceDataUse::GetResourceDataUpdate() {
DCHECK(cache_type_ == mojom::CacheType::kMemory ? is_complete_ : true);
mojom::ResourceDataUpdatePtr resource_data_update =
mojom::ResourceDataUpdate::New();
resource_data_update->request_id = resource_id();
resource_data_update->received_data_length = total_received_bytes_;
resource_data_update->delta_bytes = CalculateNewlyReceivedBytes();
resource_data_update->is_complete = is_complete_;
resource_data_update->data_reduction_proxy_compression_ratio_estimate =
data_reduction_proxy_compression_ratio_estimate_;
resource_data_update->reported_as_ad_resource = reported_as_ad_resource_;
resource_data_update->is_main_frame_resource = is_main_frame_resource_;
resource_data_update->mime_type = mime_type_;
resource_data_update->encoded_body_length = encoded_body_length_;
resource_data_update->cache_type = cache_type_;
resource_data_update->is_secure_scheme = is_secure_scheme_;
resource_data_update->proxy_used = proxy_used_;
resource_data_update->is_primary_frame_resource = is_primary_frame_resource_;
resource_data_update->origin = origin_;
return resource_data_update;
}
} // namespace page_load_metrics