| // Copyright 2025 The Chromium Authors |
| // 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_handle_impl.h" |
| |
| #include "base/functional/callback.h" |
| #include "content/browser/browser_context_impl.h" |
| #include "content/browser/preloading/prefetch/prefetch_response_reader.h" |
| #include "content/browser/preloading/prefetch/prefetch_service.h" |
| #include "content/browser/preloading/prefetch/prefetch_type.h" |
| #include "content/public/browser/preloading_data.h" |
| #include "content/public/browser/web_contents.h" |
| #include "services/network/public/cpp/url_loader_completion_status.h" |
| #include "services/network/public/mojom/url_response_head.mojom.h" |
| |
| namespace content { |
| |
| PrefetchContainerObserver::PrefetchContainerObserver() = default; |
| |
| PrefetchContainerObserver::~PrefetchContainerObserver() = default; |
| |
| void PrefetchContainerObserver::SetOnPrefetchHeadReceivedCallback( |
| base::RepeatingCallback<void(const network::mojom::URLResponseHead&)> |
| on_prefetch_head_received) { |
| on_prefetch_head_received_ = std::move(on_prefetch_head_received); |
| } |
| |
| void PrefetchContainerObserver::SetOnPrefetchCompletedOrFailedCallback( |
| base::RepeatingCallback< |
| void(const network::URLLoaderCompletionStatus& completion_status, |
| const std::optional<int>& response_code)> |
| on_prefetch_completed_or_failed) { |
| on_prefetch_completed_or_failed_ = std::move(on_prefetch_completed_or_failed); |
| } |
| |
| void PrefetchContainerObserver::OnWillBeDestroyed( |
| PrefetchContainer& prefetch_container) {} |
| |
| void PrefetchContainerObserver::OnGotInitialEligibility( |
| PrefetchContainer& prefetch_container, |
| PreloadingEligibility eligibility) {} |
| |
| void PrefetchContainerObserver::OnDeterminedHead( |
| PrefetchContainer& prefetch_container) { |
| if (on_prefetch_head_received_) { |
| // This condition will be used in a callback provided in the future. |
| // See |
| // https://chromium-review.googlesource.com/c/chromium/src/+/6615559/comment/3f439d19_8c9cf99a |
| // |
| // TODO(crbug.com/400761083): Use the callback. |
| if (prefetch_container.GetNonRedirectResponseReader() && |
| prefetch_container.GetNonRedirectResponseReader()->load_state() == |
| PrefetchResponseReader::LoadState::kResponseReceived) { |
| on_prefetch_head_received_.Run(*prefetch_container.GetNonRedirectHead()); |
| } |
| } |
| } |
| |
| void PrefetchContainerObserver::OnPrefetchCompletedOrFailed( |
| PrefetchContainer& prefetch_container, |
| const network::URLLoaderCompletionStatus& completion_status, |
| const std::optional<int>& response_code) { |
| // `IsDecoy()` check is added to preserve the existing behavior. |
| // https://crbug.com/400761083 |
| if (prefetch_container.IsDecoy()) { |
| return; |
| } |
| if (on_prefetch_completed_or_failed_) { |
| on_prefetch_completed_or_failed_.Run(completion_status, response_code); |
| } |
| } |
| |
| PrefetchHandleImpl::PrefetchHandleImpl( |
| base::WeakPtr<PrefetchService> prefetch_service, |
| base::WeakPtr<PrefetchContainer> prefetch_container) |
| : prefetch_service_(std::move(prefetch_service)), |
| prefetch_container_(std::move(prefetch_container)) { |
| CHECK(prefetch_service_); |
| // Note that `prefetch_container_` can be nullptr. |
| |
| if (prefetch_container_) { |
| prefetch_container_->AddObserver(&prefetch_container_observer_); |
| } |
| } |
| |
| PrefetchHandleImpl::~PrefetchHandleImpl() { |
| if (prefetch_container_) { |
| prefetch_container_->RemoveObserver(&prefetch_container_observer_); |
| } |
| |
| // Notify `PrefetchService` that the corresponding `PrefetchContainer` is no |
| // longer needed. `PrefetchService` might release the container and its |
| // corresponding resources by its decision with best-effort. |
| if (prefetch_service_) { |
| // TODO(crbug.com/390329781): Consider setting appropriate |
| // PrefetchStatus/PreloadingAttempt. |
| if (prefetch_status_on_release_started_prefetch_ && prefetch_container_) { |
| switch (prefetch_container_->GetLoadState()) { |
| case PrefetchContainer::LoadState::kNotStarted: |
| case PrefetchContainer::LoadState::kEligible: |
| case PrefetchContainer::LoadState::kFailedIneligible: |
| case PrefetchContainer::LoadState::kFailedHeldback: |
| break; |
| case PrefetchContainer::LoadState::kStarted: |
| case PrefetchContainer::LoadState::kDeterminedHead: |
| case PrefetchContainer::LoadState::kCompletedOrFailed: |
| prefetch_container_->SetPrefetchStatus( |
| *prefetch_status_on_release_started_prefetch_); |
| break; |
| } |
| } |
| prefetch_service_->MayReleasePrefetch(prefetch_container_); |
| } |
| } |
| |
| void PrefetchHandleImpl::SetOnPrefetchHeadReceivedCallback( |
| base::RepeatingCallback<void(const network::mojom::URLResponseHead&)> |
| on_prefetch_head_received) { |
| prefetch_container_observer_.SetOnPrefetchHeadReceivedCallback( |
| std::move(on_prefetch_head_received)); |
| } |
| |
| void PrefetchHandleImpl::SetOnPrefetchCompletedOrFailedCallback( |
| base::RepeatingCallback< |
| void(const network::URLLoaderCompletionStatus& completion_status, |
| const std::optional<int>& response_code)> |
| on_prefetch_completed_or_failed) { |
| prefetch_container_observer_.SetOnPrefetchCompletedOrFailedCallback( |
| std::move(on_prefetch_completed_or_failed)); |
| } |
| |
| bool PrefetchHandleImpl::IsAlive() const { |
| return static_cast<bool>(prefetch_container_); |
| } |
| |
| void PrefetchHandleImpl::SetPrefetchStatusOnReleaseStartedPrefetch( |
| PrefetchStatus prefetch_status_on_release_started_prefetch) { |
| CHECK(!prefetch_status_on_release_started_prefetch_); |
| prefetch_status_on_release_started_prefetch_ = |
| prefetch_status_on_release_started_prefetch; |
| } |
| |
| } // namespace content |