blob: 9dc7c878f4d24f9c98a5f45130a192141df91169 [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.
#ifndef CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_
#define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_
#include <utility>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/preloading/prefetch/prefetch_status.h"
#include "content/browser/preloading/prefetch/prefetch_type.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/speculation_host_delegate.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace network {
class SimpleURLLoader;
namespace mojom {
class CookieManager;
} // namespace mojom
} // namespace network
namespace content {
class PrefetchCookieListener;
class PrefetchDocumentManager;
class PrefetchNetworkContext;
class PrefetchService;
class PrefetchedMainframeResponseContainer;
// This class contains the state for a request to prefetch a specific URL.
class CONTENT_EXPORT PrefetchContainer {
public:
PrefetchContainer(
const GlobalRenderFrameHostId& referring_render_frame_host_id,
const GURL& url,
const PrefetchType& prefetch_type,
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager);
~PrefetchContainer();
PrefetchContainer(const PrefetchContainer&) = delete;
PrefetchContainer& operator=(const PrefetchContainer&) = delete;
// Defines the key to uniquely identify a prefetch.
using Key = std::pair<GlobalRenderFrameHostId, GURL>;
Key GetPrefetchContainerKey() const {
return std::make_pair(referring_render_frame_host_id_, url_);
}
// The ID of the render frame host that triggered the prefetch.
GlobalRenderFrameHostId GetReferringRenderFrameHostId() const {
return referring_render_frame_host_id_;
}
// The URL that will potentially be prefetched.
GURL GetURL() const { return url_; }
// The type of this prefetch. Controls how the prefetch is handled.
const PrefetchType& GetPrefetchType() const { return prefetch_type_; }
base::WeakPtr<PrefetchContainer> GetWeakPtr() const {
return weak_method_factory_.GetWeakPtr();
}
// The status of the current prefetch. Note that |HasPrefetchStatus| will be
// initially false until |SetPrefetchStatus| is called.
void SetPrefetchStatus(PrefetchStatus prefetch_status) {
prefetch_status_ = prefetch_status;
}
bool HasPrefetchStatus() const { return prefetch_status_.has_value(); }
PrefetchStatus GetPrefetchStatus() const;
// Whether this prefetch is a decoy. Decoy prefetches will not store the
// response, and not serve any prefetched resources.
void SetIsDecoy(bool is_decoy) { is_decoy_ = is_decoy; }
bool IsDecoy() const { return is_decoy_; }
// After the initial eligiblity check for |url_|, a
// |PrefetchCookieListener| listens for any changes to the cookies
// associated with |url_|. If these cookies change, then no prefetched
// resources will be served.
void RegisterCookieListener(network::mojom::CookieManager* cookie_manager);
void StopCookieListener();
bool HaveDefaultContextCookiesChanged() const;
// Before a prefetch can be served, any cookies added to the isolated network
// context must be copied over to the default network context. These functions
// are used to check and update the status of this process, as well as record
// metrics about how long this process takes.
bool IsIsolatedCookieCopyInProgress() const;
void OnIsolatedCookieCopyStart();
void OnIsolatedCookiesReadCompleteAndWriteStart();
void OnIsolatedCookieCopyComplete();
void SetOnCookieCopyCompleteCallback(base::OnceClosure callback);
// The network context used to make network requests for this prefetch.
PrefetchNetworkContext* GetOrCreateNetworkContext(
PrefetchService* prefetch_service);
PrefetchNetworkContext* GetNetworkContext() { return network_context_.get(); }
// The URL loader used to make the network requests for this prefetch.
void TakeURLLoader(std::unique_ptr<network::SimpleURLLoader> loader);
network::SimpleURLLoader* GetLoader() { return loader_.get(); }
void ResetURLLoader();
// The |PrefetchDocumentManager| that requested |this|.
PrefetchDocumentManager* GetPrefetchDocumentManager() const;
// Whether or not |this| has a prefetched response.
bool HasValidPrefetchedResponse(base::TimeDelta cacheable_duration) const;
// |this| takes ownership of the given |prefetched_response|.
void TakePrefetchedResponse(
std::unique_ptr<PrefetchedMainframeResponseContainer>
prefetched_response);
// Releases ownership of |prefetched_response_| from |this| and gives it to
// the caller.
std::unique_ptr<PrefetchedMainframeResponseContainer>
ReleasePrefetchedResponse();
// Returns request id to be used by DevTools
const std::string& RequestId() const { return request_id_; }
// Sets DevTools observer
void SetDevToolsObserver(
base::WeakPtr<content::SpeculationHostDevToolsObserver>
devtools_observer) {
devtools_observer_ = std::move(devtools_observer);
}
// Returns DevTool observer
const base::WeakPtr<SpeculationHostDevToolsObserver>& GetDevToolsObserver()
const {
return devtools_observer_;
}
private:
// The ID of the render frame host that triggered the prefetch.
GlobalRenderFrameHostId referring_render_frame_host_id_;
// The URL that will potentially be prefetched
GURL url_;
// The type of this prefetch. This controls some specific details about how
// the prefetch is handled, including whether an isolated network context or
// the default network context is used to perform the prefetch, whether or
// not the preftch proxy is used, and whether or not subresources are
// prefetched.
PrefetchType prefetch_type_;
// The |PrefetchDocumentManager| that requested |this|. Initially it owns
// |this|, but once the network request for the prefetch is started,
// ownernship is transferred to |PrefetchService|.
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager_;
// The current status, if any, of the prefetch.
absl::optional<PrefetchStatus> prefetch_status_;
// Whether this prefetch is a decoy or not. If the prefetch is a decoy then
// any prefetched resources will not be served.
bool is_decoy_ = false;
// This tracks whether the cookies associated with |url_| have changed at some
// point after the initial eligibility check.
std::unique_ptr<PrefetchCookieListener> cookie_listener_;
// The network context used to prefetch |url_|.
std::unique_ptr<PrefetchNetworkContext> network_context_;
// The URL loader used to prefetch |url_|.
std::unique_ptr<network::SimpleURLLoader> loader_;
// The prefetched response for |url_|.
std::unique_ptr<PrefetchedMainframeResponseContainer> prefetched_response_;
// The time at which |prefetched_response_| was received. This is used to
// determine whether or not |prefetched_response_| is stale.
absl::optional<base::TimeTicks> prefetch_received_time_;
// The different possible states of the cookie copy process.
enum class CookieCopyStatus {
kNotStarted,
kInProgress,
kCompleted,
};
// The current state of the cookie copy process for this prefetch.
CookieCopyStatus cookie_copy_status_ = CookieCopyStatus::kNotStarted;
// The timestamps of when the overall cookie copy process starts, and midway
// when the cookies are read from the isolated network context and are about
// to be written to the default network context.
absl::optional<base::TimeTicks> cookie_copy_start_time_;
absl::optional<base::TimeTicks> cookie_read_end_and_write_start_time_;
// A callback that runs once |cookie_copy_status_| is set to |kCompleted|.
base::OnceClosure on_cookie_copy_complete_callback_;
// Request identifier used by DevTools
std::string request_id_;
// Weak pointer to DevTools observer
base::WeakPtr<SpeculationHostDevToolsObserver> devtools_observer_;
base::WeakPtrFactory<PrefetchContainer> weak_method_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_