
Fixed: 333390326 Change-Id: I845bb1a2536b27ae57e1ad28d372fce554e6e4c2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6179528 Reviewed-by: Orr Bernstein <orrb@google.com> Reviewed-by: Kenichi Ishibashi <bashi@chromium.org> Reviewed-by: Nasko Oskov <nasko@chromium.org> Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org> Commit-Queue: Caleb Raitto <caraitto@chromium.org> Cr-Commit-Position: refs/heads/main@{#1407949}
255 lines
9.8 KiB
C++
255 lines
9.8 KiB
C++
// Copyright 2018 The Chromium Authors
|
|
// 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 <map>
|
|
#include <queue>
|
|
|
|
#include "base/containers/queue.h"
|
|
#include "base/files/file_path.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "base/timer/timer.h"
|
|
#include "content/browser/code_cache/simple_lru_cache.h"
|
|
#include "content/common/content_export.h"
|
|
#include "mojo/public/cpp/base/big_buffer.h"
|
|
#include "net/base/io_buffer.h"
|
|
#include "net/base/network_isolation_key.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::OnceCallback<void(const base::Time&, mojo_base::BigBuffer data)>;
|
|
using GetBackendCallback = base::OnceCallback<void(disk_cache::Backend*)>;
|
|
|
|
// Cache type. Used for collecting statistics for JS and Wasm in separate
|
|
// buckets.
|
|
enum CodeCacheType {
|
|
// JavaScript from http(s) pages.
|
|
kJavaScript,
|
|
|
|
// WebAssembly from http(s) pages. This cache allows more total size and
|
|
// more size per item than the JavaScript cache, since some
|
|
// WebAssembly programs are very large.
|
|
kWebAssembly,
|
|
|
|
// JavaScript from chrome and chrome-untrusted pages. The resource URLs are
|
|
// limited to only those fetched via chrome and chrome-untrusted schemes.
|
|
// The cache size is limited to disk_cache::kMaxWebUICodeCacheSize.
|
|
// Deduplication of very large items is disabled in this cache.
|
|
kWebUIJavaScript,
|
|
};
|
|
|
|
// Used for collecting statistics about cache behaviour.
|
|
// Since it's uploaded to UMA, its values must never change.
|
|
enum CacheEntryStatus : uint8_t {
|
|
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, or the empty string if key is invalid.
|
|
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(const GeneratedCodeCache&) = delete;
|
|
GeneratedCodeCache& operator=(const GeneratedCodeCache&) = delete;
|
|
|
|
~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 WriteEntry(const GURL& resource_url,
|
|
const GURL& origin_lock,
|
|
const net::NetworkIsolationKey& nik,
|
|
const base::Time& response_time,
|
|
mojo_base::BigBuffer 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,
|
|
const net::NetworkIsolationKey& nik,
|
|
ReadDataCallback);
|
|
|
|
// Delete the entry corresponding to <resource_url, origin_lock>
|
|
void DeleteEntry(const GURL& resource_url,
|
|
const GURL& origin_lock,
|
|
const net::NetworkIsolationKey& nik);
|
|
|
|
// Should be only used for tests. Sets the last accessed timestamp of an
|
|
// entry.
|
|
void SetLastUsedTimeForTest(const GURL& resource_url,
|
|
const GURL& origin_lock,
|
|
const net::NetworkIsolationKey& nik,
|
|
base::Time time,
|
|
base::OnceClosure callback);
|
|
|
|
// Clears the in-memory cache.
|
|
void ClearInMemoryCache();
|
|
|
|
void CollectStatisticsForTest(const GURL& resource_url,
|
|
const GURL& origin_lock,
|
|
GeneratedCodeCache::CacheEntryStatus status);
|
|
|
|
const base::FilePath& path() const { return path_; }
|
|
|
|
private:
|
|
class PendingOperation;
|
|
|
|
// State of the backend.
|
|
enum BackendState { kInitializing, kInitialized, kFailed };
|
|
|
|
// The operation requested.
|
|
enum Operation {
|
|
kFetch,
|
|
kFetchWithSHAKey,
|
|
kWrite,
|
|
kWriteWithSHAKey,
|
|
kDelete,
|
|
kGetBackend
|
|
};
|
|
|
|
// Data streams corresponding to each entry.
|
|
enum { kSmallDataStream = 0, kLargeDataStream = 1 };
|
|
|
|
// Creates a simple_disk_cache backend.
|
|
void CreateBackend();
|
|
void DidCreateBackend(disk_cache::BackendResult result);
|
|
|
|
// Adds operation to the appropriate queue.
|
|
void EnqueueOperation(std::unique_ptr<PendingOperation> op);
|
|
|
|
// Issues ops that were received while the backend was being initialized.
|
|
void IssuePendingOperations();
|
|
void IssueOperation(PendingOperation* op);
|
|
|
|
// Writes entry to cache.
|
|
void WriteEntryImpl(PendingOperation* op);
|
|
void OpenCompleteForWrite(PendingOperation* op,
|
|
disk_cache::EntryResult result);
|
|
void WriteSmallBufferComplete(PendingOperation* op, int rv);
|
|
void WriteLargeBufferComplete(PendingOperation* op, int rv);
|
|
void WriteComplete(PendingOperation* op);
|
|
|
|
// Fetches entry from cache.
|
|
void FetchEntryImpl(PendingOperation* op);
|
|
void OpenCompleteForRead(PendingOperation* op,
|
|
disk_cache::EntryResult result);
|
|
void ReadSmallBufferComplete(PendingOperation* op, int rv);
|
|
void ReadLargeBufferComplete(PendingOperation* op, int rv);
|
|
void ReadComplete(PendingOperation* op);
|
|
|
|
// Deletes entry from cache.
|
|
void DeleteEntryImpl(PendingOperation* op);
|
|
|
|
void DoomEntry(PendingOperation* op);
|
|
|
|
// Issues the next operation on the queue for |key|.
|
|
void IssueNextOperation(const std::string& key);
|
|
// Removes |op| and issues the next operation on its queue.
|
|
void CloseOperationAndIssueNext(PendingOperation* op);
|
|
|
|
// Enqueues the operation issues it if there are no pending operations for
|
|
// its key.
|
|
void EnqueueOperationAndIssueIfNext(std::unique_ptr<PendingOperation> op);
|
|
// Dequeues the operation and transfers ownership to caller.
|
|
std::unique_ptr<PendingOperation> DequeueOperation(PendingOperation* op);
|
|
|
|
void DoPendingGetBackend(PendingOperation* op);
|
|
|
|
void OpenCompleteForSetLastUsedForTest(base::Time time,
|
|
base::OnceClosure callback,
|
|
disk_cache::EntryResult result);
|
|
|
|
void CollectStatistics(const GURL& resource_url,
|
|
const GURL& origin_lock,
|
|
GeneratedCodeCache::CacheEntryStatus status);
|
|
|
|
// Whether very large cache entries are deduplicated in this cache.
|
|
// Deduplication is disabled in the WebUI code cache, as an additional defense
|
|
// against privilege escalation in case there is a bug in the deduplication
|
|
// logic.
|
|
bool IsDeduplicationEnabled() const;
|
|
|
|
bool ShouldDeduplicateEntry(uint32_t data_size) const;
|
|
|
|
// Checks that the header data in the small buffer is valid. We may read cache
|
|
// entries that were written by a previous version of Chrome which uses
|
|
// obsolete formats. These reads should fail and be doomed as soon as
|
|
// possible.
|
|
bool IsValidHeader(scoped_refptr<net::IOBufferWithSize> small_buffer) const;
|
|
|
|
std::unique_ptr<disk_cache::Backend> backend_;
|
|
BackendState backend_state_;
|
|
|
|
// Queue for operations received while initializing the backend.
|
|
using PendingOperationQueue = base::queue<std::unique_ptr<PendingOperation>>;
|
|
PendingOperationQueue pending_ops_;
|
|
|
|
// Map from key to queue of pending operations.
|
|
std::map<std::string, PendingOperationQueue> active_entries_map_;
|
|
|
|
base::FilePath path_;
|
|
int max_size_bytes_;
|
|
CodeCacheType cache_type_;
|
|
|
|
// A hypothetical memory-backed code cache. Used to collect UMAs.
|
|
SimpleLruCache lru_cache_;
|
|
static constexpr int64_t kLruCacheCapacity = 50 * 1024 * 1024;
|
|
|
|
base::WeakPtrFactory<GeneratedCodeCache> weak_ptr_factory_{this};
|
|
};
|
|
|
|
} // namespace content
|
|
|
|
#endif // CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_H_
|