blob: 9f60ea565157dd7d9336142efef262ee6a467018 [file] [log] [blame]
// Copyright 2022 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 "content/browser/preloading/prefetch/prefetch_container.h"
#include <memory>
#include "base/callback.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "content/browser/preloading/prefetch/prefetch_cookie_listener.h"
#include "content/browser/preloading/prefetch/prefetch_document_manager.h"
#include "content/browser/preloading/prefetch/prefetch_network_context.h"
#include "content/browser/preloading/prefetch/prefetch_service.h"
#include "content/browser/preloading/prefetch/prefetch_status.h"
#include "content/browser/preloading/prefetch/prefetch_type.h"
#include "content/browser/preloading/prefetch/prefetched_mainframe_response_container.h"
#include "content/public/browser/global_routing_id.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "url/gurl.h"
namespace content {
namespace {
void RecordCookieCopyTimes(
const base::TimeTicks& cookie_copy_start_time,
const base::TimeTicks& cookie_read_end_and_write_start_time,
const base::TimeTicks& cookie_copy_end_time) {
UMA_HISTOGRAM_CUSTOM_TIMES(
"PrefetchProxy.AfterClick.Mainframe.CookieReadTime",
cookie_read_end_and_write_start_time - cookie_copy_start_time,
base::TimeDelta(), base::Seconds(5), 50);
UMA_HISTOGRAM_CUSTOM_TIMES(
"PrefetchProxy.AfterClick.Mainframe.CookieWriteTime",
cookie_copy_end_time - cookie_read_end_and_write_start_time,
base::TimeDelta(), base::Seconds(5), 50);
UMA_HISTOGRAM_CUSTOM_TIMES(
"PrefetchProxy.AfterClick.Mainframe.CookieCopyTime",
cookie_copy_end_time - cookie_copy_start_time, base::TimeDelta(),
base::Seconds(5), 50);
}
} // namespace
PrefetchContainer::PrefetchContainer(
const GlobalRenderFrameHostId& referring_render_frame_host_id,
const GURL& url,
const PrefetchType& prefetch_type,
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager)
: referring_render_frame_host_id_(referring_render_frame_host_id),
url_(url),
prefetch_type_(prefetch_type),
prefetch_document_manager_(prefetch_document_manager),
request_id_(base::UnguessableToken::Create().ToString()) {}
PrefetchContainer::~PrefetchContainer() = default;
PrefetchStatus PrefetchContainer::GetPrefetchStatus() const {
DCHECK(prefetch_status_);
return prefetch_status_.value();
}
PrefetchNetworkContext* PrefetchContainer::GetOrCreateNetworkContext(
PrefetchService* prefetch_service) {
if (!network_context_) {
network_context_ = std::make_unique<PrefetchNetworkContext>(
prefetch_service, prefetch_type_);
}
return network_context_.get();
}
PrefetchDocumentManager* PrefetchContainer::GetPrefetchDocumentManager() const {
return prefetch_document_manager_.get();
}
void PrefetchContainer::RegisterCookieListener(
network::mojom::CookieManager* cookie_manager) {
cookie_listener_ =
PrefetchCookieListener::MakeAndRegister(url_, cookie_manager);
}
void PrefetchContainer::StopCookieListener() {
if (cookie_listener_)
cookie_listener_->StopListening();
}
bool PrefetchContainer::HaveDefaultContextCookiesChanged() const {
if (cookie_listener_)
return cookie_listener_->HaveCookiesChanged();
return false;
}
bool PrefetchContainer::IsIsolatedCookieCopyInProgress() const {
switch (cookie_copy_status_) {
case CookieCopyStatus::kNotStarted:
case CookieCopyStatus::kCompleted:
return false;
case CookieCopyStatus::kInProgress:
return true;
}
}
void PrefetchContainer::OnIsolatedCookieCopyStart() {
DCHECK(!IsIsolatedCookieCopyInProgress());
// We don't want the cookie listener for this URL to get the changes from the
// copy.
StopCookieListener();
cookie_copy_status_ = CookieCopyStatus::kInProgress;
cookie_copy_start_time_ = base::TimeTicks::Now();
}
void PrefetchContainer::OnIsolatedCookiesReadCompleteAndWriteStart() {
DCHECK(IsIsolatedCookieCopyInProgress());
cookie_read_end_and_write_start_time_ = base::TimeTicks::Now();
}
void PrefetchContainer::OnIsolatedCookieCopyComplete() {
DCHECK(IsIsolatedCookieCopyInProgress());
cookie_copy_status_ = CookieCopyStatus::kCompleted;
if (cookie_copy_start_time_.has_value() &&
cookie_read_end_and_write_start_time_.has_value()) {
RecordCookieCopyTimes(*cookie_copy_start_time_,
*cookie_read_end_and_write_start_time_,
base::TimeTicks::Now());
}
if (on_cookie_copy_complete_callback_)
std::move(on_cookie_copy_complete_callback_).Run();
}
void PrefetchContainer::SetOnCookieCopyCompleteCallback(
base::OnceClosure callback) {
DCHECK(IsIsolatedCookieCopyInProgress());
on_cookie_copy_complete_callback_ = std::move(callback);
}
void PrefetchContainer::TakeURLLoader(
std::unique_ptr<network::SimpleURLLoader> loader) {
DCHECK(!loader_);
loader_ = std::move(loader);
}
void PrefetchContainer::ResetURLLoader() {
DCHECK(loader_);
loader_.reset();
}
bool PrefetchContainer::HasValidPrefetchedResponse(
base::TimeDelta cacheable_duration) const {
return prefetched_response_ != nullptr &&
prefetch_received_time_.has_value() &&
base::TimeTicks::Now() <
prefetch_received_time_.value() + cacheable_duration;
}
void PrefetchContainer::TakePrefetchedResponse(
std::unique_ptr<PrefetchedMainframeResponseContainer> prefetched_response) {
DCHECK(!prefetched_response_);
DCHECK(!is_decoy_);
prefetch_received_time_ = base::TimeTicks::Now();
prefetched_response_ = std::move(prefetched_response);
}
std::unique_ptr<PrefetchedMainframeResponseContainer>
PrefetchContainer::ReleasePrefetchedResponse() {
prefetch_received_time_.reset();
return std::move(prefetched_response_);
}
} // namespace content