| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SERVICES_NETWORK_PREFETCH_URL_LOADER_CLIENT_H_ |
| #define SERVICES_NETWORK_PREFETCH_URL_LOADER_CLIENT_H_ |
| |
| #include "base/containers/linked_list.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/time/time.h" |
| #include "base/types/pass_key.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "net/base/network_isolation_key.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/mojom/url_loader.mojom.h" |
| #include "url/gurl.h" |
| |
| namespace network { |
| |
| class PrefetchCache; |
| |
| // An implementation of PrefetchURLLoaderClient that is used for prefetches. It |
| // can cache ongoing requests until they are requests by a render process, and |
| // then forward on the callbacks that were received. |
| class COMPONENT_EXPORT(NETWORK_SERVICE) PrefetchURLLoaderClient final |
| : public mojom::URLLoaderClient, |
| public base::LinkNode<PrefetchURLLoaderClient> { |
| public: |
| // Use PrefetchCache::Emplace() to create a PrefetchURLLoaderClient object. |
| PrefetchURLLoaderClient(base::PassKey<PrefetchCache>, |
| const net::NetworkIsolationKey& nik, |
| const ResourceRequest& request, |
| base::TimeTicks expiry_time, |
| PrefetchCache* prefetch_cache); |
| |
| PrefetchURLLoaderClient(const PrefetchURLLoaderClient&) = delete; |
| PrefetchURLLoaderClient& operator=(const PrefetchURLLoaderClient&) = delete; |
| |
| // PrefetchURLLoaderClient is owned by the PrefetchCache. This destructor |
| // should never be called directly. |
| ~PrefetchURLLoaderClient() final; |
| |
| // Accessors used by NetworkContext::PrefetchCache. |
| const net::NetworkIsolationKey& network_isolation_key() const { |
| return network_isolation_key_; |
| } |
| |
| const GURL& url() const { return request_.url; } |
| |
| base::TimeTicks expiry_time() const { return expiry_time_; } |
| |
| // Returns a PendingReceiver that can be passed to a URLLoaderFactory. Should |
| // only be called once. |
| mojo::PendingReceiver<mojom::URLLoader> GetURLLoaderPendingReceiver(); |
| |
| // Returns a PendingRemote that can be passed to a URLLoaderFactory. Should |
| // only be called once. |
| mojo::PendingRemote<mojom::URLLoaderClient> BindNewPipeAndPassRemote(); |
| |
| // Returns true if `request_` is similar enough to `real_request_` that it can |
| // be used to serve it. |
| bool Matches(const ResourceRequest& real_request) const; |
| |
| // Binds this response to a request from a client. Sets `real_client_` and |
| // replays any callbacks that have been received up until this point. Once |
| // this has been called, the object's lifetime is tied to the remotes and it |
| // will instruct PrefetchCache to delete it if it loses connection to |
| // `real_client_` or the URLLoader. Calling Consume() may delete `this`. |
| void Consume(mojo::PendingReceiver<mojom::URLLoader> loader, |
| mojo::PendingRemote<mojom::URLLoaderClient> client); |
| |
| // Implementation of mojom::URLLoaderClient. Each of these methods forwards |
| // the arguments in `real_client_` if it has been set, otherwise caches the |
| // arguments in `pending_callbacks_`. |
| void OnReceiveEarlyHints(mojom::EarlyHintsPtr early_hints) override; |
| void OnReceiveResponse( |
| mojom::URLResponseHeadPtr head, |
| mojo::ScopedDataPipeConsumerHandle body, |
| std::optional<mojo_base::BigBuffer> cached_metadata) override; |
| void OnReceiveRedirect(const net::RedirectInfo& redirect_info, |
| mojom::URLResponseHeadPtr head) override; |
| void OnUploadProgress(int64_t current_position, |
| int64_t total_size, |
| OnUploadProgressCallback callback) override; |
| void OnTransferSizeUpdated(int32_t transfer_size_diff) override; |
| void OnComplete(const URLLoaderCompletionStatus& status) override; |
| |
| private: |
| // Deletes this object if `real_client_` has been initialized. Otherwise |
| // sets the `disconnected_` flag to remind itself to delete itself later. |
| void OnDisconnect(); |
| |
| // Calls `method` with `args` if `real_client_` has been set, otherwise |
| // records the call in `pending_callbacks_` to replay later. |
| template <typename Method, typename... Args> |
| void ForwardOrRecord(Method method, Args... args); |
| |
| // Calls `method` with `args` on `real_client_`. |
| template <typename Method, typename... Args> |
| void ForwardToRealClient(Method method, Args... args); |
| |
| const ResourceRequest request_; |
| const net::NetworkIsolationKey network_isolation_key_; |
| const base::TimeTicks expiry_time_; |
| |
| // Callbacks that have been called prior to a render process consuming this |
| // request that need to be replayed. |
| std::vector<base::OnceClosure> pending_callbacks_; |
| |
| // This is initialized once a render process consumes this request. |
| mojo::Remote<mojom::URLLoaderClient> real_client_; |
| |
| // This is initialized at construction. |
| mojo::Receiver<mojom::URLLoaderClient> receiver_{this}; |
| |
| // This is initialized when the request is started. It is unbound again when |
| // Consume() is called. |
| mojo::Remote<mojom::URLLoader> url_loader_; |
| |
| // A pointer to the PrefetchCache object that created and owns us. |
| const raw_ptr<PrefetchCache> prefetch_cache_; |
| |
| // Set to true when we lose a mojo connection. |
| bool disconnected_ = false; |
| }; |
| |
| } // namespace network |
| |
| #endif // SERVICES_NETWORK_PREFETCH_URL_LOADER_CLIENT_H_ |