|  | // 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. | 
|  |  | 
|  | #ifndef ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_H_ | 
|  | #define ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_H_ | 
|  |  | 
|  | #include "base/containers/circular_deque.h" | 
|  | #include "base/memory/raw_ref.h" | 
|  | #include "content/public/browser/browser_context.h" | 
|  | #include "content/public/browser/browser_thread.h" | 
|  | #include "content/public/browser/prefetch_handle.h" | 
|  | #include "content/public/browser/prefetch_request_status_listener.h" | 
|  | #include "net/http/http_no_vary_search_data.h" | 
|  | #include "net/http/http_request_headers.h" | 
|  | #include "services/network/public/cpp/resource_request.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | namespace android_webview { | 
|  |  | 
|  | // The default TTL value in `//content` is 10 minutes which is too long for most | 
|  | // of WebView cases. This value here can change in the future and that shouldn't | 
|  | // affect the `//content` TTL default value. | 
|  | inline constexpr int DEFAULT_TTL_IN_SEC = 60; | 
|  | // The MaxPrefetches number is not present in the `//content` layer, so it is | 
|  | // specific to WebView. | 
|  | inline constexpr size_t DEFAULT_MAX_PREFETCHES = 10; | 
|  | // This is the source of truth for the absolute maximum number of prefetches | 
|  | // that can ever be cached in WebView. It can override the number set by the | 
|  | // AndroidX API. | 
|  | inline constexpr int32_t ABSOLUTE_MAX_PREFETCHES = 20; | 
|  | // Returned from `AwPrefetchManager::StartPrefetchRequest` if the prefetch | 
|  | // request was unsuccessful (i.e. there is no key for the prefetch). | 
|  | inline constexpr int NO_PREFETCH_KEY = -1; | 
|  |  | 
|  | // The suffix used for generating `//content` prefetch internal histogram names | 
|  | // recorded per trigger. | 
|  | // TODO(crbug.com/379140429): Merge this with prerender one. | 
|  | inline constexpr char AW_PREFETCH_METRICS_SUFFIX[] = "WebView"; | 
|  |  | 
|  | // Manages prefetch operations for this Profile. | 
|  | // Lifetime: Profile | 
|  | class AwPrefetchManager { | 
|  | public: | 
|  | explicit AwPrefetchManager(content::BrowserContext* browser_context); | 
|  |  | 
|  | AwPrefetchManager(const AwPrefetchManager&) = delete; | 
|  | AwPrefetchManager& operator=(const AwPrefetchManager&) = delete; | 
|  |  | 
|  | ~AwPrefetchManager(); | 
|  |  | 
|  | // Returns `true` if the `resource_request` is also a prefetch request. | 
|  | // NOTE: A prefetch request can also be a prerender request i.e. | 
|  | // this method & `IsPrerenderRequest` can both return `true` for it, | 
|  | // however this is not always the case. | 
|  | static bool IsPrefetchRequest( | 
|  | const network::ResourceRequest& resource_request); | 
|  |  | 
|  | // Returns `true` if the `resource_request` is also a prerender request. | 
|  | // NOTE: A prerender request will always be a prefetch request i.e. | 
|  | // this method & `IsPrefetchRequest` will always return `true` for it | 
|  | // as prefetching a always required for prerendering. | 
|  | static bool IsPrerenderRequest( | 
|  | const network::ResourceRequest& resource_request); | 
|  |  | 
|  | // Returns `true` if the `blink::kSecPurposeHeaderName` header is associated | 
|  | // with a prefetch request. | 
|  | static bool IsSecPurposeForPrefetch( | 
|  | std::optional<std::string> sec_purpose_header_value); | 
|  |  | 
|  | // Returns the key associated with the outgoing prefetch request | 
|  | // and thus the prefetch handle inside of `all_prefetches_map_` (if | 
|  | // successful), otherwise returns `NO_PREFETCH_KEY`. | 
|  | int StartPrefetchRequest( | 
|  | JNIEnv* env, | 
|  | const std::string& url, | 
|  | const base::android::JavaParamRef<jobject>& prefetch_params, | 
|  | const base::android::JavaParamRef<jobject>& callback, | 
|  | const base::android::JavaParamRef<jobject>& callback_executor); | 
|  |  | 
|  | void CancelPrefetch(JNIEnv* env, jint prefetch_key); | 
|  |  | 
|  | bool GetIsPrefetchInCacheForTesting(JNIEnv* env, jint prefetch_key); | 
|  |  | 
|  | // Updates Time-To-Live (TTL) for the prefetched content in seconds. | 
|  | void SetTtlInSec(JNIEnv* env, jint ttl_in_sec) { ttl_in_sec_ = ttl_in_sec; } | 
|  |  | 
|  | // Updates the maximum number of allowed prefetches in cache | 
|  | void SetMaxPrefetches(JNIEnv* env, jint max_prefetches) { | 
|  | max_prefetches_ = std::min(max_prefetches, ABSOLUTE_MAX_PREFETCHES); | 
|  | } | 
|  |  | 
|  | // Returns the Time-to-Live (TTL) for prefetched content in seconds. | 
|  | jint GetTtlInSec(JNIEnv* env) const { return ttl_in_sec_; } | 
|  |  | 
|  | // Returns the maximum number of allowed prefetches in cache. | 
|  | jint GetMaxPrefetches(JNIEnv* env) const { return max_prefetches_; } | 
|  |  | 
|  | // Returns the key associated with the prefetch handle inside of | 
|  | // `all_prefetches_map_`. | 
|  | int AddPrefetchHandle( | 
|  | std::unique_ptr<content::PrefetchHandle> prefetch_handle) { | 
|  | CHECK(prefetch_handle); | 
|  | CHECK(max_prefetches_ > 0u); | 
|  | CHECK(all_prefetches_map_.size() < max_prefetches_); | 
|  |  | 
|  | const int32_t new_prefetch_key = GetNextPrefetchKey(); | 
|  | all_prefetches_map_[new_prefetch_key] = std::move(prefetch_handle); | 
|  | UpdateLastPrefetchKey(new_prefetch_key); | 
|  | return new_prefetch_key; | 
|  | } | 
|  |  | 
|  | std::vector<int32_t> GetAllPrefetchKeysForTesting() const { | 
|  | std::vector<int32_t> prefetch_keys; | 
|  | prefetch_keys.reserve(all_prefetches_map_.size()); | 
|  | for (const auto& prefetch_pair : all_prefetches_map_) { | 
|  | prefetch_keys.push_back(prefetch_pair.first); | 
|  | } | 
|  | return prefetch_keys; | 
|  | } | 
|  |  | 
|  | int GetLastPrefetchKeyForTesting() const { return last_prefetch_key_; } | 
|  |  | 
|  | base::android::ScopedJavaLocalRef<jobject> GetJavaPrefetchManager(); | 
|  |  | 
|  | private: | 
|  | raw_ref<content::BrowserContext> browser_context_; | 
|  |  | 
|  | int ttl_in_sec_ = DEFAULT_TTL_IN_SEC; | 
|  |  | 
|  | size_t max_prefetches_ = DEFAULT_MAX_PREFETCHES; | 
|  |  | 
|  | std::map<int32_t, std::unique_ptr<content::PrefetchHandle>> | 
|  | all_prefetches_map_; | 
|  |  | 
|  | // Java object reference. | 
|  | base::android::ScopedJavaGlobalRef<jobject> java_obj_; | 
|  |  | 
|  | // Should only be incremented. Acts as an "order added" mechanism | 
|  | // inside of `all_prefetches_map_` since `std::map` stores keys | 
|  | // in a sorted order. | 
|  | int32_t last_prefetch_key_ = -1; | 
|  |  | 
|  | int32_t GetNextPrefetchKey() const { return last_prefetch_key_ + 1; } | 
|  |  | 
|  | void UpdateLastPrefetchKey(int new_key) { | 
|  | CHECK(new_key > last_prefetch_key_); | 
|  | last_prefetch_key_ = new_key; | 
|  | } | 
|  | }; | 
|  |  | 
|  | }  // namespace android_webview | 
|  |  | 
|  | #endif  // ANDROID_WEBVIEW_BROWSER_PREFETCH_AW_PREFETCH_MANAGER_H_ |