blob: a41f0296c23da9b94cc5a08cd2084f2128059a3c [file] [log] [blame]
// Copyright 2016 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/data_use_measurement/chrome_data_use_ascriber.h"
#include "base/memory/ptr_util.h"
#include "components/data_use_measurement/content/content_url_request_classifier.h"
#include "components/data_use_measurement/core/data_use_recorder.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/data_use_measurement/core/url_request_classifier.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "net/url_request/url_request.h"
namespace data_use_measurement {
// static
const void* ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
kUserDataKey = static_cast<void*>(
&ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::kUserDataKey);
ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
DataUseRecorderEntryAsUserData(DataUseRecorderEntry entry)
: entry_(entry) {}
ChromeDataUseAscriber::DataUseRecorderEntryAsUserData::
~DataUseRecorderEntryAsUserData() {}
ChromeDataUseAscriber::ChromeDataUseAscriber() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
ChromeDataUseAscriber::~ChromeDataUseAscriber() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK_EQ(0u, data_use_recorders_.size());
}
DataUseRecorder* ChromeDataUseAscriber::GetDataUseRecorder(
net::URLRequest* request) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
return nullptr;
}
void ChromeDataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// TODO(kundaji): Handle PlzNavigate.
if (content::IsBrowserSideNavigationEnabled())
return;
auto service = static_cast<DataUseUserData*>(
request->GetUserData(DataUseUserData::kUserDataKey));
if (service)
return;
const content::ResourceRequestInfo* request_info =
content::ResourceRequestInfo::ForRequest(request);
content::ResourceType resource_type = request_info
? request_info->GetResourceType()
: content::RESOURCE_TYPE_LAST_TYPE;
if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
return;
int render_process_id = -1;
int render_frame_id = -1;
bool has_valid_render_frame_id =
content::ResourceRequestInfo::GetRenderFrameForRequest(
request, &render_process_id, &render_frame_id);
DCHECK(has_valid_render_frame_id);
// Browser tests may not set up DataUseWebContentsObservers in which case
// this class never sees navigation and frame events so DataUseRecorders
// will never be destroyed. To avoid this, we ignore requests whose
// render frames don't have a record. However, this can also be caused by
// URLRequests racing the frame create events.
// TODO(kundaji): Add UMA.
if (render_frame_data_use_map_.find(
RenderFrameHostID(render_process_id, render_frame_id)) ==
render_frame_data_use_map_.end()) {
return;
}
// If this request is already being tracked, do not create a new entry.
auto user_data = static_cast<DataUseRecorderEntryAsUserData*>(
request->GetUserData(DataUseRecorderEntryAsUserData::kUserDataKey));
if (user_data)
return;
DataUseRecorderEntry entry = data_use_recorders_.insert(
data_use_recorders_.end(), base::MakeUnique<DataUseRecorder>());
request->SetUserData(DataUseRecorderEntryAsUserData::kUserDataKey,
new DataUseRecorderEntryAsUserData(entry));
pending_navigation_data_use_map_.insert(
std::make_pair(request_info->GetGlobalRequestID(), entry));
}
void ChromeDataUseAscriber::OnUrlRequestDestroyed(net::URLRequest* request) {
const content::ResourceRequestInfo* request_info =
content::ResourceRequestInfo::ForRequest(request);
content::ResourceType resource_type = request_info
? request_info->GetResourceType()
: content::RESOURCE_TYPE_LAST_TYPE;
if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
// If request was not successful, then ReadyToCommitNavigation will not be
// called. So delete the pending navigation DataUseRecorderEntry here.
if (!request->status().is_success()) {
DeletePendingNavigationEntry(request_info->GetGlobalRequestID());
}
}
}
void ChromeDataUseAscriber::RenderFrameCreated(int render_process_id,
int render_frame_id,
int parent_render_process_id,
int parent_render_frame_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// TODO(kundaji): Point child render frames to the same DataUseRecorder as
// parent render frame.
DataUseRecorderEntry entry = data_use_recorders_.insert(
data_use_recorders_.end(), base::MakeUnique<DataUseRecorder>());
render_frame_data_use_map_.insert(std::make_pair(
RenderFrameHostID(render_process_id, render_frame_id), entry));
}
void ChromeDataUseAscriber::RenderFrameDeleted(int render_process_id,
int render_frame_id,
int parent_render_process_id,
int parent_render_frame_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
RenderFrameHostID key(render_process_id, render_frame_id);
auto frame_iter = render_frame_data_use_map_.find(key);
DCHECK(frame_iter != render_frame_data_use_map_.end());
DataUseRecorderEntry entry = frame_iter->second;
render_frame_data_use_map_.erase(frame_iter);
data_use_recorders_.erase(entry);
}
void ChromeDataUseAscriber::DidStartMainFrameNavigation(
GURL gurl,
int render_process_id,
int render_frame_id,
void* navigation_handle) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
void ChromeDataUseAscriber::ReadyToCommitMainFrameNavigation(
GURL gurl,
content::GlobalRequestID global_request_id,
int render_process_id,
int render_frame_id,
bool is_same_page_navigation,
void* navigation_handle) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// TODO(kundaji): Move the DataUseRecorderEntry from pending navigation map
// to render frame map if |is_same_page_navigation| is true. Otherwise,
// merge it with the DataUseRecorderEntry in the render frame map.
DeletePendingNavigationEntry(global_request_id);
}
void ChromeDataUseAscriber::DidRedirectMainFrameNavigation(
GURL gurl,
int render_process_id,
int render_frame_id,
void* navigation_handle) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
void ChromeDataUseAscriber::DeletePendingNavigationEntry(
content::GlobalRequestID global_request_id) {
auto navigation_iter =
pending_navigation_data_use_map_.find(global_request_id);
// Pending navigation entry will not be found if finish navigation
// raced the URLRequest.
if (navigation_iter != pending_navigation_data_use_map_.end()) {
auto entry = navigation_iter->second;
pending_navigation_data_use_map_.erase(navigation_iter);
data_use_recorders_.erase(entry);
}
}
std::unique_ptr<URLRequestClassifier>
ChromeDataUseAscriber::CreateURLRequestClassifier() const {
return base::MakeUnique<ContentURLRequestClassifier>();
}
} // namespace data_use_measurement