| // Copyright 2018 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_CODE_CACHE_GENERATED_CODE_CACHE_H_ |
| #define CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_H_ |
| |
| #include <queue> |
| |
| #include "base/containers/queue.h" |
| #include "base/files/file_path.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "content/common/content_export.h" |
| #include "net/base/completion_callback.h" |
| #include "net/base/io_buffer.h" |
| #include "net/disk_cache/disk_cache.h" |
| #include "url/origin.h" |
| |
| namespace content { |
| |
| // Cache for storing generated code from the renderer on the disk. This cache |
| // uses |resource_url| + |origin_lock| as a key for storing the generated code. |
| // |resource_url| is the url corresponding to the requested resource. |
| // |origin_lock| is the origin that the renderer which requested this resource |
| // is locked to. This is used to enforce site isolation policy on cached code. |
| // For example, if SitePerProcess is enabled and http://script.com/script1.js is |
| // requested by http://example.com, then http://script.com/script.js is the |
| // resource_url and http://example.com is the origin_lock. |
| // |
| // The key is generated by concatenating the serialized url and origin lock |
| // with a separator in between. The separator is non-valid URL characters, to |
| // prevent any attacks by crafting the URLs. |origin_lock| could be empty when |
| // renderer is not locked to an origin (ex:SitePerProcess is disabled) and it |
| // is safe to use only |resource_url| as the key in such cases. |
| // |
| // This uses a simple disk_cache backend. It just stores one data stream and |
| // stores response_time + generated code as one data blob. |
| // |
| // There exists one cache per storage partition and is owned by the storage |
| // partition. This cache is created, accessed and destroyed on the I/O |
| // thread. |
| class CONTENT_EXPORT GeneratedCodeCache { |
| public: |
| using ReadDataCallback = |
| base::RepeatingCallback<void(const base::Time&, |
| const std::vector<uint8_t>&)>; |
| using GetBackendCallback = base::OnceCallback<void(disk_cache::Backend*)>; |
| static const int kResponseTimeSizeInBytes = sizeof(int64_t); |
| |
| // Cache type. Used for collecting statistics for JS and Wasm in separate |
| // buckets. |
| enum CodeCacheType { kJavaScript, kWebAssembly }; |
| |
| // Used for collecting statistics about cache behaviour. |
| enum CacheEntryStatus { |
| kHit, |
| kMiss, |
| kClear, |
| kUpdate, |
| kCreate, |
| kError, |
| kIncompleteEntry, |
| kWriteFailed, |
| kMaxValue = kWriteFailed |
| }; |
| |
| // Returns the resource URL from the key. The key has the format prefix + |
| // resource URL + separator + requesting origin. This function extracts and |
| // returns resource URL from the key. |
| static std::string GetResourceURLFromKey(const std::string& key); |
| |
| // Creates a GeneratedCodeCache with the specified path and the maximum size. |
| // If |max_size_bytes| is 0, then disk_cache picks a default size based on |
| // some heuristics. |
| GeneratedCodeCache(const base::FilePath& path, |
| int max_size_bytes, |
| CodeCacheType cache_type); |
| |
| ~GeneratedCodeCache(); |
| |
| // Runs the callback with a raw pointer to the backend. If we could not create |
| // the backend then it will return a null. This runs the callback |
| // synchronously if the backend is already open or asynchronously on the |
| // completion of a pending backend creation. |
| void GetBackend(GetBackendCallback callback); |
| |
| // Writes data to the cache. If there is an entry corresponding to |
| // <|resource_url|, |origin_lock|> this overwrites the existing data. If |
| // there is no entry it creates a new one. |
| void WriteData(const GURL& resource_url, |
| const GURL& origin_lock, |
| const base::Time& response_time, |
| const std::vector<uint8_t>& data); |
| |
| // Fetch entry corresponding to <resource_url, origin_lock> from the cache |
| // and return it using the ReadDataCallback. |
| void FetchEntry(const GURL& resource_url, |
| const GURL& origin_lock, |
| ReadDataCallback); |
| |
| // Delete the entry corresponding to <resource_url, origin_lock> |
| void DeleteEntry(const GURL& resource_url, const GURL& origin_lock); |
| |
| // Should be only used for tests. Sets the last accessed timestamp of an |
| // entry. |
| void SetLastUsedTimeForTest(const GURL& resource_url, |
| const GURL& origin_lock, |
| base::Time time, |
| base::RepeatingCallback<void(void)> callback); |
| |
| const base::FilePath& path() const { return path_; } |
| |
| private: |
| class PendingOperation; |
| using ScopedBackendPtr = std::unique_ptr<disk_cache::Backend>; |
| |
| // State of the backend. |
| enum BackendState { kInitializing, kInitialized, kFailed }; |
| |
| // The operation requested. |
| enum Operation { kFetch, kWrite, kDelete, kGetBackend }; |
| |
| // Data streams corresponding to each entry. |
| enum { kDataIndex = 1 }; |
| |
| // Creates a simple_disk_cache backend. |
| void CreateBackend(); |
| void DidCreateBackend( |
| scoped_refptr<base::RefCountedData<ScopedBackendPtr>> backend_ptr, |
| int rv); |
| |
| // The requests that are received while tha backend is being initialized |
| // are recorded in pending operations list. This function issues all pending |
| // operations. |
| void IssuePendingOperations(); |
| |
| // Write entry to cache |
| void WriteDataImpl(const std::string& key, |
| scoped_refptr<net::IOBufferWithSize> buffer); |
| void CompleteForWriteData( |
| scoped_refptr<net::IOBufferWithSize> buffer, |
| const std::string& key, |
| scoped_refptr<base::RefCountedData<disk_cache::EntryWithOpened>> |
| entry_struct, |
| int rv); |
| void WriteDataCompleted(const std::string& key, int rv); |
| |
| // Fetch entry from cache |
| void FetchEntryImpl(const std::string& key, ReadDataCallback); |
| void OpenCompleteForReadData( |
| ReadDataCallback callback, |
| const std::string& key, |
| scoped_refptr<base::RefCountedData<disk_cache::Entry*>> entry, |
| int rv); |
| void ReadDataComplete(const std::string& key, |
| ReadDataCallback callback, |
| scoped_refptr<net::IOBufferWithSize> buffer, |
| int rv); |
| |
| // Delete entry from cache |
| void DeleteEntryImpl(const std::string& key); |
| |
| // Issues the queued operation at the front of the queue for the given |key|. |
| void IssueQueuedOperationForEntry(const std::string& key); |
| // Enqueues into the list if there is an in-progress operation. Otherwise |
| // creates an entry to indicate there is an active operation. |
| bool EnqueueAsPendingOperation(const std::string& key, |
| std::unique_ptr<PendingOperation> op); |
| void IssueOperation(PendingOperation* op); |
| |
| void DoPendingGetBackend(GetBackendCallback callback); |
| |
| void OpenCompleteForSetLastUsedForTest( |
| scoped_refptr<base::RefCountedData<disk_cache::Entry*>> entry, |
| base::Time time, |
| base::RepeatingCallback<void(void)> callback, |
| int rv); |
| |
| void CollectStatistics(GeneratedCodeCache::CacheEntryStatus status); |
| |
| std::unique_ptr<disk_cache::Backend> backend_; |
| BackendState backend_state_; |
| |
| std::vector<std::unique_ptr<PendingOperation>> pending_ops_; |
| |
| // Map from key to queue ops. |
| std::map<std::string, base::queue<std::unique_ptr<PendingOperation>>> |
| active_entries_map_; |
| |
| base::FilePath path_; |
| int max_size_bytes_; |
| CodeCacheType cache_type_; |
| |
| base::WeakPtrFactory<GeneratedCodeCache> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(GeneratedCodeCache); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_H_ |