blob: 38476630c2c3f54e9b1ecae1796138abac42511b [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_SERVICE_H_
#define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_SERVICE_H_
#include <map>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/preloading/prefetch/prefetch_container.h"
#include "content/browser/preloading/prefetch/prefetch_status.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_routing_id.h"
#include "net/cookies/canonical_cookie.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace base {
class OneShotTimer;
} // namespace base
namespace network::mojom {
class URLLoaderFactory;
} // namespace network::mojom
namespace net {
class IsolationInfo;
} // namespace net
namespace content {
class BrowserContext;
class PrefetchProxyConfigurator;
class PrefetchServiceDelegate;
class ServiceWorkerContext;
// Manages all prefetches within a single BrowserContext. Responsible for
// checking the eligibility of the prefetch, making the network request for the
// prefetch, and provide prefetched resources to URL loader interceptor when
// needed.
class CONTENT_EXPORT PrefetchService {
public:
// |browser_context| must outlive this instance. In general this should always
// be true, since |PrefetchService| will be indirectly owned by
// |BrowserContext|.
static std::unique_ptr<PrefetchService> CreateIfPossible(
BrowserContext* browser_context);
explicit PrefetchService(BrowserContext* browser_context);
virtual ~PrefetchService();
PrefetchService(const PrefetchService&) = delete;
const PrefetchService& operator=(const PrefetchService&) = delete;
BrowserContext* GetBrowserContext() const { return browser_context_; }
PrefetchServiceDelegate* GetPrefetchServiceDelegate() const {
return delegate_.get();
}
PrefetchProxyConfigurator* GetPrefetchProxyConfigurator() const {
return prefetch_proxy_configurator_.get();
}
virtual void PrefetchUrl(base::WeakPtr<PrefetchContainer> prefetch_container);
// Called when a navigation to the URL associated with |prefetch_container| is
// likely to occur in the immediate future.
void PrepareToServe(base::WeakPtr<PrefetchContainer> prefetch_container);
// Returns the prefetch with |url| that is ready to serve. In order for a
// prefetch to be ready to serve, |PrepareToServe| must have been previously
// called with the prefetch.
base::WeakPtr<PrefetchContainer> GetPrefetchToServe(const GURL& url) const;
// Returns the current prefetches associated with |this|. Used to check the
// state of the prefetches.
// TODO(https://crbug.com/1299059): Remove this once we can get metrics
// instead.
const std::map<PrefetchContainer::Key, base::WeakPtr<PrefetchContainer>>&
GetAllPrefetchesForTesting() {
return all_prefetches_;
}
// Helper functions to control the behavior of the eligibility check when
// testing.
static void SetServiceWorkerContextForTesting(ServiceWorkerContext* context);
static void SetHostNonUniqueFilterForTesting(
bool (*filter)(base::StringPiece));
// Sets the URLLoaderFactory to be used during testing instead of the
// |PrefetchNetworkContext| associated with each |PrefetchContainer|. Note
// that this does not take ownership of |url_loader_factory|, and caller must
// keep ownership over the course of the test.
static void SetURLLoaderFactoryForTesting(
network::mojom::URLLoaderFactory* url_loader_factory);
private:
// Checks whether the given |prefetch_container| is eligible for prefetch.
// Once the eligibility is determined then |result_callback| will be called
// with result and an optional status stating why the prefetch is not
// eligible.
using OnEligibilityResultCallback =
base::OnceCallback<void(base::WeakPtr<PrefetchContainer>,
bool eligible,
absl::optional<PrefetchStatus> status)>;
void CheckEligibilityOfPrefetch(
base::WeakPtr<PrefetchContainer> prefetch_container,
OnEligibilityResultCallback result_callback) const;
// Called after getting the existing cookies associated with
// |prefetch_container|. If there are any cookies, then the prefetch is not
// eligible.
void OnGotCookiesForEligibilityCheck(
base::WeakPtr<PrefetchContainer> prefetch_container,
OnEligibilityResultCallback result_callback,
const net::CookieAccessResultList& cookie_list,
const net::CookieAccessResultList& excluded_cookies) const;
// Called once the eligibility of |prefetch_container| is determined. If the
// prefetch is eligible it is added to the queue to be prefetched. If it is
// not eligible, then we consider making it a decoy request.
void OnGotEligibilityResult(
base::WeakPtr<PrefetchContainer> prefetch_container,
bool eligible,
absl::optional<PrefetchStatus> status);
// Starts the network requests for as many prefetches in |prefetch_queue_| as
// possible.
void Prefetch();
// Pops the first valid prefetch from |prefetch_queue_|. If there are no
// valid prefetches in the queue, then nullptr is returned. In this context,
// for a prefetch to be valid, it must not be null and it must be on a visible
// web contents.
base::WeakPtr<PrefetchContainer> PopNextPrefetchContainer();
// Once the network request for a prefetch starts, ownership is transferred
// from the referring |PrefetchDocumentManager| to |this|. After
// |PrefetchContainerLifetimeInPrefetchService| amount of time, the prefetch
// is deleted. Note that if |PrefetchContainerLifetimeInPrefetchService| is 0
// or less, then it is kept forever.
void TakeOwnershipOfPrefetch(
base::WeakPtr<PrefetchContainer> prefetch_container);
void ResetPrefetch(base::WeakPtr<PrefetchContainer> prefetch_container);
// Starts the network request for the given |prefetch_container|.
void StartSinglePrefetch(base::WeakPtr<PrefetchContainer> prefetch_container);
// Gets the URL loader for the given |prefetch_container|. If an override was
// set by |SetURLLoaderFactoryForTesting|, then that will be returned instead.
network::mojom::URLLoaderFactory* GetURLLoaderFactory(
base::WeakPtr<PrefetchContainer> prefetch_container);
// Called when the request for |prefetch_container| is redirected.
void OnPrefetchRedirect(base::WeakPtr<PrefetchContainer> prefetch_container,
const net::RedirectInfo& redirect_info,
const network::mojom::URLResponseHead& response_head,
std::vector<std::string>* removed_headers);
// Called when the request for |prefetch_container| is completed.
void OnPrefetchComplete(base::WeakPtr<PrefetchContainer> prefetch_container,
const net::IsolationInfo& isolation_info,
std::unique_ptr<std::string> body);
// Checks the response form |OnPrefechComplete| for success or failure. On
// success, the response is moved to a |PrefetchedMainframeResponseContainer|
// and cached in |prefetch_contianer|.
void HandlePrefetchedResponse(
base::WeakPtr<PrefetchContainer> prefetch_container,
const net::IsolationInfo& isolation_info,
network::mojom::URLResponseHeadPtr head,
std::unique_ptr<std::string> body);
// Copies any cookies in the isolated network context associated with
// |prefetch_container| to the default network context.
void CopyIsolatedCookies(base::WeakPtr<PrefetchContainer> prefetch_container);
void OnGotIsolatedCookiesForCopy(
base::WeakPtr<PrefetchContainer> prefetch_container,
const net::CookieAccessResultList& cookie_list,
const net::CookieAccessResultList& excluded_cookies);
// Checks if there is a prefetch in |all_prefetches_| with the same URL as
// |prefetch_container| but from a different referring render frame host.
// Records the result to a UMA histogram.
void RecordExistingPrefetchWithMatchingURL(
base::WeakPtr<PrefetchContainer> prefetch_container) const;
raw_ptr<BrowserContext> browser_context_;
// Delegate provided by embedder that controls specific behavior of |this|.
// May be nullptr if embedder doesn't provide a delegate.
std::unique_ptr<PrefetchServiceDelegate> delegate_;
// The custom proxy configurator for Prefetch Proxy. Only used on prefetches
// that require the proxy.
std::unique_ptr<PrefetchProxyConfigurator> prefetch_proxy_configurator_;
// All prefetches associated with |this| regardless of ownership.
std::map<PrefetchContainer::Key, base::WeakPtr<PrefetchContainer>>
all_prefetches_;
// A FIFO queue of prefetches that have been confirmed to be eligible but have
// not started yet.
std::vector<base::WeakPtr<PrefetchContainer>> prefetch_queue_;
// The number of prefetches with in progress requests.
int num_active_prefetches_{0};
// Prefetches owned by |this|. Once the network request for a prefetch is
// started, |this| takes ownership of the prefetch so the response can be used
// on future page loads. A timer of
// |PrefetchContainerLifetimeInPrefetchService| is set that deletes the
// prefetch. If |PrefetchContainerLifetimeInPrefetchService| zero or less,
// then, the prefetch is kept forever.
std::map<PrefetchContainer::Key,
std::pair<std::unique_ptr<PrefetchContainer>,
std::unique_ptr<base::OneShotTimer>>>
owned_prefetches_;
// The set of prefetches that are ready to serve. In order to be in this map,
// the prefetch must also be in |owned_prefetches_|, have a valid prefetched
// response, and have started the cookie copy process. A prefetch is added to
// this map when |PrepareToServe| is called on it, and once in this map, it
// can be returned by |GetPrefetchToServe|.
std::map<GURL, base::WeakPtr<PrefetchContainer>> prefetches_ready_to_serve_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<PrefetchService> weak_method_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_SERVICE_H_