1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/http/http_cache.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <optional>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/format_macros.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/memory/ref_counted.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros_local.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/pickle.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/time/default_clock.h"
34*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
35*6777b538SAndroid Build Coastguard Worker #include "http_request_info.h"
36*6777b538SAndroid Build Coastguard Worker #include "net/base/cache_type.h"
37*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
38*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
39*6777b538SAndroid Build Coastguard Worker #include "net/base/load_flags.h"
40*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
41*6777b538SAndroid Build Coastguard Worker #include "net/base/network_anonymization_key.h"
42*6777b538SAndroid Build Coastguard Worker #include "net/base/network_isolation_key.h"
43*6777b538SAndroid Build Coastguard Worker #include "net/base/upload_data_stream.h"
44*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/disk_cache.h"
45*6777b538SAndroid Build Coastguard Worker #include "net/http/http_cache_transaction.h"
46*6777b538SAndroid Build Coastguard Worker #include "net/http/http_cache_writers.h"
47*6777b538SAndroid Build Coastguard Worker #include "net/http/http_network_layer.h"
48*6777b538SAndroid Build Coastguard Worker #include "net/http/http_network_session.h"
49*6777b538SAndroid Build Coastguard Worker #include "net/http/http_request_info.h"
50*6777b538SAndroid Build Coastguard Worker #include "net/http/http_response_headers.h"
51*6777b538SAndroid Build Coastguard Worker #include "net/http/http_response_info.h"
52*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
53*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_with_source.h"
54*6777b538SAndroid Build Coastguard Worker #include "net/quic/quic_server_info.h"
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX)
57*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
58*6777b538SAndroid Build Coastguard Worker #endif
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker namespace net {
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker namespace {
63*6777b538SAndroid Build Coastguard Worker // True if any HTTP cache has been initialized.
64*6777b538SAndroid Build Coastguard Worker bool g_init_cache = false;
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker // True if split cache is enabled by default. Must be set before any HTTP cache
67*6777b538SAndroid Build Coastguard Worker // has been initialized.
68*6777b538SAndroid Build Coastguard Worker bool g_enable_split_cache = false;
69*6777b538SAndroid Build Coastguard Worker } // namespace
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker const char HttpCache::kDoubleKeyPrefix[] = "_dk_";
72*6777b538SAndroid Build Coastguard Worker const char HttpCache::kDoubleKeySeparator[] = " ";
73*6777b538SAndroid Build Coastguard Worker const char HttpCache::kSubframeDocumentResourcePrefix[] = "s_";
74*6777b538SAndroid Build Coastguard Worker
DefaultBackend(CacheType type,BackendType backend_type,scoped_refptr<disk_cache::BackendFileOperationsFactory> file_operations_factory,const base::FilePath & path,int max_bytes,bool hard_reset)75*6777b538SAndroid Build Coastguard Worker HttpCache::DefaultBackend::DefaultBackend(
76*6777b538SAndroid Build Coastguard Worker CacheType type,
77*6777b538SAndroid Build Coastguard Worker BackendType backend_type,
78*6777b538SAndroid Build Coastguard Worker scoped_refptr<disk_cache::BackendFileOperationsFactory>
79*6777b538SAndroid Build Coastguard Worker file_operations_factory,
80*6777b538SAndroid Build Coastguard Worker const base::FilePath& path,
81*6777b538SAndroid Build Coastguard Worker int max_bytes,
82*6777b538SAndroid Build Coastguard Worker bool hard_reset)
83*6777b538SAndroid Build Coastguard Worker : type_(type),
84*6777b538SAndroid Build Coastguard Worker backend_type_(backend_type),
85*6777b538SAndroid Build Coastguard Worker file_operations_factory_(std::move(file_operations_factory)),
86*6777b538SAndroid Build Coastguard Worker path_(path),
87*6777b538SAndroid Build Coastguard Worker max_bytes_(max_bytes),
88*6777b538SAndroid Build Coastguard Worker hard_reset_(hard_reset) {}
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker HttpCache::DefaultBackend::~DefaultBackend() = default;
91*6777b538SAndroid Build Coastguard Worker
92*6777b538SAndroid Build Coastguard Worker // static
InMemory(int max_bytes)93*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HttpCache::BackendFactory> HttpCache::DefaultBackend::InMemory(
94*6777b538SAndroid Build Coastguard Worker int max_bytes) {
95*6777b538SAndroid Build Coastguard Worker return std::make_unique<DefaultBackend>(MEMORY_CACHE, CACHE_BACKEND_DEFAULT,
96*6777b538SAndroid Build Coastguard Worker /*file_operations_factory=*/nullptr,
97*6777b538SAndroid Build Coastguard Worker base::FilePath(), max_bytes, false);
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker
CreateBackend(NetLog * net_log,base::OnceCallback<void (disk_cache::BackendResult)> callback)100*6777b538SAndroid Build Coastguard Worker disk_cache::BackendResult HttpCache::DefaultBackend::CreateBackend(
101*6777b538SAndroid Build Coastguard Worker NetLog* net_log,
102*6777b538SAndroid Build Coastguard Worker base::OnceCallback<void(disk_cache::BackendResult)> callback) {
103*6777b538SAndroid Build Coastguard Worker DCHECK_GE(max_bytes_, 0);
104*6777b538SAndroid Build Coastguard Worker disk_cache::ResetHandling reset_handling =
105*6777b538SAndroid Build Coastguard Worker hard_reset_ ? disk_cache::ResetHandling::kReset
106*6777b538SAndroid Build Coastguard Worker : disk_cache::ResetHandling::kResetOnError;
107*6777b538SAndroid Build Coastguard Worker LOCAL_HISTOGRAM_BOOLEAN("HttpCache.HardReset", hard_reset_);
108*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
109*6777b538SAndroid Build Coastguard Worker if (app_status_listener_getter_) {
110*6777b538SAndroid Build Coastguard Worker return disk_cache::CreateCacheBackend(
111*6777b538SAndroid Build Coastguard Worker type_, backend_type_, file_operations_factory_, path_, max_bytes_,
112*6777b538SAndroid Build Coastguard Worker reset_handling, net_log, std::move(callback),
113*6777b538SAndroid Build Coastguard Worker app_status_listener_getter_);
114*6777b538SAndroid Build Coastguard Worker }
115*6777b538SAndroid Build Coastguard Worker #endif
116*6777b538SAndroid Build Coastguard Worker return disk_cache::CreateCacheBackend(
117*6777b538SAndroid Build Coastguard Worker type_, backend_type_, file_operations_factory_, path_, max_bytes_,
118*6777b538SAndroid Build Coastguard Worker reset_handling, net_log, std::move(callback));
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
SetAppStatusListenerGetter(disk_cache::ApplicationStatusListenerGetter app_status_listener_getter)122*6777b538SAndroid Build Coastguard Worker void HttpCache::DefaultBackend::SetAppStatusListenerGetter(
123*6777b538SAndroid Build Coastguard Worker disk_cache::ApplicationStatusListenerGetter app_status_listener_getter) {
124*6777b538SAndroid Build Coastguard Worker app_status_listener_getter_ = std::move(app_status_listener_getter);
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker #endif
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker //-----------------------------------------------------------------------------
129*6777b538SAndroid Build Coastguard Worker
ActiveEntry(base::WeakPtr<HttpCache> cache,disk_cache::Entry * entry,bool opened_in)130*6777b538SAndroid Build Coastguard Worker HttpCache::ActiveEntry::ActiveEntry(base::WeakPtr<HttpCache> cache,
131*6777b538SAndroid Build Coastguard Worker disk_cache::Entry* entry,
132*6777b538SAndroid Build Coastguard Worker bool opened_in)
133*6777b538SAndroid Build Coastguard Worker : cache_(std::move(cache)), disk_entry_(entry), opened_(opened_in) {
134*6777b538SAndroid Build Coastguard Worker CHECK(disk_entry_);
135*6777b538SAndroid Build Coastguard Worker cache_->active_entries_.emplace(disk_entry_->GetKey(),
136*6777b538SAndroid Build Coastguard Worker base::raw_ref<ActiveEntry>::from_ptr(this));
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker
~ActiveEntry()139*6777b538SAndroid Build Coastguard Worker HttpCache::ActiveEntry::~ActiveEntry() {
140*6777b538SAndroid Build Coastguard Worker if (cache_) {
141*6777b538SAndroid Build Coastguard Worker if (doomed_) {
142*6777b538SAndroid Build Coastguard Worker FinalizeDoomed();
143*6777b538SAndroid Build Coastguard Worker } else {
144*6777b538SAndroid Build Coastguard Worker Deactivate();
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker
FinalizeDoomed()149*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::FinalizeDoomed() {
150*6777b538SAndroid Build Coastguard Worker CHECK(doomed_);
151*6777b538SAndroid Build Coastguard Worker
152*6777b538SAndroid Build Coastguard Worker auto it =
153*6777b538SAndroid Build Coastguard Worker cache_->doomed_entries_.find(base::raw_ref<ActiveEntry>::from_ptr(this));
154*6777b538SAndroid Build Coastguard Worker CHECK(it != cache_->doomed_entries_.end());
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Worker cache_->doomed_entries_.erase(it);
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker
Deactivate()159*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::Deactivate() {
160*6777b538SAndroid Build Coastguard Worker CHECK(!doomed_);
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker std::string key = disk_entry_->GetKey();
163*6777b538SAndroid Build Coastguard Worker if (key.empty()) {
164*6777b538SAndroid Build Coastguard Worker SlowDeactivate();
165*6777b538SAndroid Build Coastguard Worker return;
166*6777b538SAndroid Build Coastguard Worker }
167*6777b538SAndroid Build Coastguard Worker
168*6777b538SAndroid Build Coastguard Worker auto it = cache_->active_entries_.find(key);
169*6777b538SAndroid Build Coastguard Worker CHECK(it != cache_->active_entries_.end());
170*6777b538SAndroid Build Coastguard Worker CHECK(&it->second.get() == this);
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker cache_->active_entries_.erase(it);
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker // TODO(ricea): Add unit test for this method.
SlowDeactivate()176*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::SlowDeactivate() {
177*6777b538SAndroid Build Coastguard Worker CHECK(cache_);
178*6777b538SAndroid Build Coastguard Worker // We don't know this entry's key so we have to find it without it.
179*6777b538SAndroid Build Coastguard Worker for (auto it = cache_->active_entries_.begin();
180*6777b538SAndroid Build Coastguard Worker it != cache_->active_entries_.end(); ++it) {
181*6777b538SAndroid Build Coastguard Worker if (&it->second.get() == this) {
182*6777b538SAndroid Build Coastguard Worker cache_->active_entries_.erase(it);
183*6777b538SAndroid Build Coastguard Worker return;
184*6777b538SAndroid Build Coastguard Worker }
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker
TransactionInReaders(Transaction * transaction) const188*6777b538SAndroid Build Coastguard Worker bool HttpCache::ActiveEntry::TransactionInReaders(
189*6777b538SAndroid Build Coastguard Worker Transaction* transaction) const {
190*6777b538SAndroid Build Coastguard Worker return readers_.count(transaction) > 0;
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker
ReleaseWriters()193*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::ReleaseWriters() {
194*6777b538SAndroid Build Coastguard Worker // May destroy `this`.
195*6777b538SAndroid Build Coastguard Worker writers_.reset();
196*6777b538SAndroid Build Coastguard Worker }
197*6777b538SAndroid Build Coastguard Worker
AddTransactionToWriters(Transaction * transaction,ParallelWritingPattern parallel_writing_pattern)198*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::AddTransactionToWriters(
199*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
200*6777b538SAndroid Build Coastguard Worker ParallelWritingPattern parallel_writing_pattern) {
201*6777b538SAndroid Build Coastguard Worker CHECK(cache_);
202*6777b538SAndroid Build Coastguard Worker if (!writers_) {
203*6777b538SAndroid Build Coastguard Worker writers_ =
204*6777b538SAndroid Build Coastguard Worker std::make_unique<Writers>(cache_.get(), base::WrapRefCounted(this));
205*6777b538SAndroid Build Coastguard Worker } else {
206*6777b538SAndroid Build Coastguard Worker ParallelWritingPattern writers_pattern;
207*6777b538SAndroid Build Coastguard Worker DCHECK(writers_->CanAddWriters(&writers_pattern));
208*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(PARALLEL_WRITING_JOIN, writers_pattern);
209*6777b538SAndroid Build Coastguard Worker }
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker Writers::TransactionInfo info(transaction->partial(),
212*6777b538SAndroid Build Coastguard Worker transaction->is_truncated(),
213*6777b538SAndroid Build Coastguard Worker *(transaction->GetResponseInfo()));
214*6777b538SAndroid Build Coastguard Worker
215*6777b538SAndroid Build Coastguard Worker writers_->AddTransaction(transaction, parallel_writing_pattern,
216*6777b538SAndroid Build Coastguard Worker transaction->priority(), info);
217*6777b538SAndroid Build Coastguard Worker }
218*6777b538SAndroid Build Coastguard Worker
Doom()219*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::Doom() {
220*6777b538SAndroid Build Coastguard Worker doomed_ = true;
221*6777b538SAndroid Build Coastguard Worker disk_entry_->Doom();
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker
RestartHeadersPhaseTransactions()224*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::RestartHeadersPhaseTransactions() {
225*6777b538SAndroid Build Coastguard Worker if (headers_transaction_) {
226*6777b538SAndroid Build Coastguard Worker RestartHeadersTransaction();
227*6777b538SAndroid Build Coastguard Worker }
228*6777b538SAndroid Build Coastguard Worker
229*6777b538SAndroid Build Coastguard Worker auto it = done_headers_queue_.begin();
230*6777b538SAndroid Build Coastguard Worker while (it != done_headers_queue_.end()) {
231*6777b538SAndroid Build Coastguard Worker Transaction* done_headers_transaction = *it;
232*6777b538SAndroid Build Coastguard Worker it = done_headers_queue_.erase(it);
233*6777b538SAndroid Build Coastguard Worker done_headers_transaction->cache_io_callback().Run(net::ERR_CACHE_RACE);
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker }
236*6777b538SAndroid Build Coastguard Worker
RestartHeadersTransaction()237*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::RestartHeadersTransaction() {
238*6777b538SAndroid Build Coastguard Worker Transaction* headers_transaction = headers_transaction_;
239*6777b538SAndroid Build Coastguard Worker headers_transaction_ = nullptr;
240*6777b538SAndroid Build Coastguard Worker // May destroy `this`.
241*6777b538SAndroid Build Coastguard Worker headers_transaction->SetValidatingCannotProceed();
242*6777b538SAndroid Build Coastguard Worker }
243*6777b538SAndroid Build Coastguard Worker
ProcessAddToEntryQueue()244*6777b538SAndroid Build Coastguard Worker void HttpCache::ActiveEntry::ProcessAddToEntryQueue() {
245*6777b538SAndroid Build Coastguard Worker DCHECK(!add_to_entry_queue_.empty());
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker // Note `this` may be new or may already have a response body written to it.
248*6777b538SAndroid Build Coastguard Worker // In both cases, a transaction needs to wait since only one transaction can
249*6777b538SAndroid Build Coastguard Worker // be in the headers phase at a time.
250*6777b538SAndroid Build Coastguard Worker if (headers_transaction_) {
251*6777b538SAndroid Build Coastguard Worker return;
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker Transaction* transaction = add_to_entry_queue_.front();
254*6777b538SAndroid Build Coastguard Worker add_to_entry_queue_.erase(add_to_entry_queue_.begin());
255*6777b538SAndroid Build Coastguard Worker headers_transaction_ = transaction;
256*6777b538SAndroid Build Coastguard Worker
257*6777b538SAndroid Build Coastguard Worker transaction->cache_io_callback().Run(OK);
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
RemovePendingTransaction(Transaction * transaction)260*6777b538SAndroid Build Coastguard Worker bool HttpCache::ActiveEntry::RemovePendingTransaction(
261*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
262*6777b538SAndroid Build Coastguard Worker auto j =
263*6777b538SAndroid Build Coastguard Worker find(add_to_entry_queue_.begin(), add_to_entry_queue_.end(), transaction);
264*6777b538SAndroid Build Coastguard Worker if (j == add_to_entry_queue_.end()) {
265*6777b538SAndroid Build Coastguard Worker return false;
266*6777b538SAndroid Build Coastguard Worker }
267*6777b538SAndroid Build Coastguard Worker
268*6777b538SAndroid Build Coastguard Worker add_to_entry_queue_.erase(j);
269*6777b538SAndroid Build Coastguard Worker return true;
270*6777b538SAndroid Build Coastguard Worker }
271*6777b538SAndroid Build Coastguard Worker
TakeAllQueuedTransactions()272*6777b538SAndroid Build Coastguard Worker HttpCache::TransactionList HttpCache::ActiveEntry::TakeAllQueuedTransactions() {
273*6777b538SAndroid Build Coastguard Worker // Process done_headers_queue before add_to_entry_queue to maintain FIFO
274*6777b538SAndroid Build Coastguard Worker // order.
275*6777b538SAndroid Build Coastguard Worker TransactionList list = std::move(done_headers_queue_);
276*6777b538SAndroid Build Coastguard Worker done_headers_queue_.clear();
277*6777b538SAndroid Build Coastguard Worker list.splice(list.end(), add_to_entry_queue_);
278*6777b538SAndroid Build Coastguard Worker add_to_entry_queue_.clear();
279*6777b538SAndroid Build Coastguard Worker return list;
280*6777b538SAndroid Build Coastguard Worker }
281*6777b538SAndroid Build Coastguard Worker
CanTransactionWriteResponseHeaders(Transaction * transaction,bool is_partial,bool is_match) const282*6777b538SAndroid Build Coastguard Worker bool HttpCache::ActiveEntry::CanTransactionWriteResponseHeaders(
283*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
284*6777b538SAndroid Build Coastguard Worker bool is_partial,
285*6777b538SAndroid Build Coastguard Worker bool is_match) const {
286*6777b538SAndroid Build Coastguard Worker // If |transaction| is the current writer, do nothing. This can happen for
287*6777b538SAndroid Build Coastguard Worker // range requests since they can go back to headers phase after starting to
288*6777b538SAndroid Build Coastguard Worker // write.
289*6777b538SAndroid Build Coastguard Worker if (writers_ && writers_->HasTransaction(transaction)) {
290*6777b538SAndroid Build Coastguard Worker CHECK(is_partial);
291*6777b538SAndroid Build Coastguard Worker return true;
292*6777b538SAndroid Build Coastguard Worker }
293*6777b538SAndroid Build Coastguard Worker
294*6777b538SAndroid Build Coastguard Worker if (transaction != headers_transaction_) {
295*6777b538SAndroid Build Coastguard Worker return false;
296*6777b538SAndroid Build Coastguard Worker }
297*6777b538SAndroid Build Coastguard Worker
298*6777b538SAndroid Build Coastguard Worker if (!(transaction->mode() & Transaction::WRITE)) {
299*6777b538SAndroid Build Coastguard Worker return false;
300*6777b538SAndroid Build Coastguard Worker }
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Worker // If its not a match then check if it is the transaction responsible for
303*6777b538SAndroid Build Coastguard Worker // writing the response body.
304*6777b538SAndroid Build Coastguard Worker if (!is_match) {
305*6777b538SAndroid Build Coastguard Worker return (!writers_ || writers_->IsEmpty()) && done_headers_queue_.empty() &&
306*6777b538SAndroid Build Coastguard Worker readers_.empty();
307*6777b538SAndroid Build Coastguard Worker }
308*6777b538SAndroid Build Coastguard Worker
309*6777b538SAndroid Build Coastguard Worker return true;
310*6777b538SAndroid Build Coastguard Worker }
311*6777b538SAndroid Build Coastguard Worker
312*6777b538SAndroid Build Coastguard Worker //-----------------------------------------------------------------------------
313*6777b538SAndroid Build Coastguard Worker
314*6777b538SAndroid Build Coastguard Worker // This structure keeps track of work items that are attempting to create or
315*6777b538SAndroid Build Coastguard Worker // open cache entries or the backend itself.
316*6777b538SAndroid Build Coastguard Worker struct HttpCache::PendingOp {
317*6777b538SAndroid Build Coastguard Worker PendingOp() = default;
318*6777b538SAndroid Build Coastguard Worker ~PendingOp() = default;
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker raw_ptr<disk_cache::Entry, AcrossTasksDanglingUntriaged> entry = nullptr;
321*6777b538SAndroid Build Coastguard Worker bool entry_opened = false; // rather than created.
322*6777b538SAndroid Build Coastguard Worker
323*6777b538SAndroid Build Coastguard Worker std::unique_ptr<disk_cache::Backend> backend;
324*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WorkItem> writer;
325*6777b538SAndroid Build Coastguard Worker // True if there is a posted OnPendingOpComplete() task that might delete
326*6777b538SAndroid Build Coastguard Worker // |this| without removing it from |pending_ops_|. Note that since
327*6777b538SAndroid Build Coastguard Worker // OnPendingOpComplete() is static, it will not get cancelled when HttpCache
328*6777b538SAndroid Build Coastguard Worker // is destroyed.
329*6777b538SAndroid Build Coastguard Worker bool callback_will_delete = false;
330*6777b538SAndroid Build Coastguard Worker WorkItemList pending_queue;
331*6777b538SAndroid Build Coastguard Worker };
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker //-----------------------------------------------------------------------------
334*6777b538SAndroid Build Coastguard Worker
335*6777b538SAndroid Build Coastguard Worker // A work item encapsulates a single request to the backend with all the
336*6777b538SAndroid Build Coastguard Worker // information needed to complete that request.
337*6777b538SAndroid Build Coastguard Worker class HttpCache::WorkItem {
338*6777b538SAndroid Build Coastguard Worker public:
WorkItem(WorkItemOperation operation,Transaction * transaction,scoped_refptr<ActiveEntry> * entry)339*6777b538SAndroid Build Coastguard Worker WorkItem(WorkItemOperation operation,
340*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
341*6777b538SAndroid Build Coastguard Worker scoped_refptr<ActiveEntry>* entry)
342*6777b538SAndroid Build Coastguard Worker : operation_(operation), transaction_(transaction), entry_(entry) {}
WorkItem(WorkItemOperation operation,Transaction * transaction,CompletionOnceCallback callback)343*6777b538SAndroid Build Coastguard Worker WorkItem(WorkItemOperation operation,
344*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
345*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback)
346*6777b538SAndroid Build Coastguard Worker : operation_(operation),
347*6777b538SAndroid Build Coastguard Worker transaction_(transaction),
348*6777b538SAndroid Build Coastguard Worker entry_(nullptr),
349*6777b538SAndroid Build Coastguard Worker callback_(std::move(callback)) {}
350*6777b538SAndroid Build Coastguard Worker ~WorkItem() = default;
351*6777b538SAndroid Build Coastguard Worker
352*6777b538SAndroid Build Coastguard Worker // Calls back the transaction with the result of the operation.
NotifyTransaction(int result,scoped_refptr<ActiveEntry> entry)353*6777b538SAndroid Build Coastguard Worker void NotifyTransaction(int result, scoped_refptr<ActiveEntry> entry) {
354*6777b538SAndroid Build Coastguard Worker if (entry_) {
355*6777b538SAndroid Build Coastguard Worker *entry_ = std::move(entry);
356*6777b538SAndroid Build Coastguard Worker }
357*6777b538SAndroid Build Coastguard Worker if (transaction_) {
358*6777b538SAndroid Build Coastguard Worker transaction_->cache_io_callback().Run(result);
359*6777b538SAndroid Build Coastguard Worker }
360*6777b538SAndroid Build Coastguard Worker }
361*6777b538SAndroid Build Coastguard Worker
362*6777b538SAndroid Build Coastguard Worker // Notifies the caller about the operation completion. Returns true if the
363*6777b538SAndroid Build Coastguard Worker // callback was invoked.
DoCallback(int result)364*6777b538SAndroid Build Coastguard Worker bool DoCallback(int result) {
365*6777b538SAndroid Build Coastguard Worker if (!callback_.is_null()) {
366*6777b538SAndroid Build Coastguard Worker std::move(callback_).Run(result);
367*6777b538SAndroid Build Coastguard Worker return true;
368*6777b538SAndroid Build Coastguard Worker }
369*6777b538SAndroid Build Coastguard Worker return false;
370*6777b538SAndroid Build Coastguard Worker }
371*6777b538SAndroid Build Coastguard Worker
operation()372*6777b538SAndroid Build Coastguard Worker WorkItemOperation operation() { return operation_; }
ClearTransaction()373*6777b538SAndroid Build Coastguard Worker void ClearTransaction() { transaction_ = nullptr; }
ClearEntry()374*6777b538SAndroid Build Coastguard Worker void ClearEntry() { entry_ = nullptr; }
ClearCallback()375*6777b538SAndroid Build Coastguard Worker void ClearCallback() { callback_.Reset(); }
Matches(Transaction * transaction) const376*6777b538SAndroid Build Coastguard Worker bool Matches(Transaction* transaction) const {
377*6777b538SAndroid Build Coastguard Worker return transaction == transaction_;
378*6777b538SAndroid Build Coastguard Worker }
IsValid() const379*6777b538SAndroid Build Coastguard Worker bool IsValid() const {
380*6777b538SAndroid Build Coastguard Worker return transaction_ || entry_ || !callback_.is_null();
381*6777b538SAndroid Build Coastguard Worker }
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker private:
384*6777b538SAndroid Build Coastguard Worker WorkItemOperation operation_;
385*6777b538SAndroid Build Coastguard Worker raw_ptr<Transaction, DanglingUntriaged> transaction_;
386*6777b538SAndroid Build Coastguard Worker raw_ptr<scoped_refptr<ActiveEntry>, DanglingUntriaged> entry_;
387*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback_; // User callback.
388*6777b538SAndroid Build Coastguard Worker };
389*6777b538SAndroid Build Coastguard Worker
390*6777b538SAndroid Build Coastguard Worker //-----------------------------------------------------------------------------
391*6777b538SAndroid Build Coastguard Worker
HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,std::unique_ptr<BackendFactory> backend_factory)392*6777b538SAndroid Build Coastguard Worker HttpCache::HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,
393*6777b538SAndroid Build Coastguard Worker std::unique_ptr<BackendFactory> backend_factory)
394*6777b538SAndroid Build Coastguard Worker : net_log_(nullptr),
395*6777b538SAndroid Build Coastguard Worker backend_factory_(std::move(backend_factory)),
396*6777b538SAndroid Build Coastguard Worker
397*6777b538SAndroid Build Coastguard Worker network_layer_(std::move(network_layer)),
398*6777b538SAndroid Build Coastguard Worker clock_(base::DefaultClock::GetInstance()) {
399*6777b538SAndroid Build Coastguard Worker g_init_cache = true;
400*6777b538SAndroid Build Coastguard Worker HttpNetworkSession* session = network_layer_->GetSession();
401*6777b538SAndroid Build Coastguard Worker // Session may be NULL in unittests.
402*6777b538SAndroid Build Coastguard Worker // TODO(mmenke): Seems like tests could be changed to provide a session,
403*6777b538SAndroid Build Coastguard Worker // rather than having logic only used in unit tests here.
404*6777b538SAndroid Build Coastguard Worker if (!session) {
405*6777b538SAndroid Build Coastguard Worker return;
406*6777b538SAndroid Build Coastguard Worker }
407*6777b538SAndroid Build Coastguard Worker
408*6777b538SAndroid Build Coastguard Worker net_log_ = session->net_log();
409*6777b538SAndroid Build Coastguard Worker }
410*6777b538SAndroid Build Coastguard Worker
~HttpCache()411*6777b538SAndroid Build Coastguard Worker HttpCache::~HttpCache() {
412*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
413*6777b538SAndroid Build Coastguard Worker // Transactions should see an invalid cache after this point; otherwise they
414*6777b538SAndroid Build Coastguard Worker // could see an inconsistent object (half destroyed).
415*6777b538SAndroid Build Coastguard Worker weak_factory_.InvalidateWeakPtrs();
416*6777b538SAndroid Build Coastguard Worker
417*6777b538SAndroid Build Coastguard Worker active_entries_.clear();
418*6777b538SAndroid Build Coastguard Worker doomed_entries_.clear();
419*6777b538SAndroid Build Coastguard Worker
420*6777b538SAndroid Build Coastguard Worker // Before deleting pending_ops_, we have to make sure that the disk cache is
421*6777b538SAndroid Build Coastguard Worker // done with said operations, or it will attempt to use deleted data.
422*6777b538SAndroid Build Coastguard Worker disk_cache_.reset();
423*6777b538SAndroid Build Coastguard Worker
424*6777b538SAndroid Build Coastguard Worker for (auto& pending_it : pending_ops_) {
425*6777b538SAndroid Build Coastguard Worker // We are not notifying the transactions about the cache going away, even
426*6777b538SAndroid Build Coastguard Worker // though they are waiting for a callback that will never fire.
427*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = pending_it.second;
428*6777b538SAndroid Build Coastguard Worker pending_op->writer.reset();
429*6777b538SAndroid Build Coastguard Worker bool delete_pending_op = true;
430*6777b538SAndroid Build Coastguard Worker if (building_backend_ && pending_op->callback_will_delete) {
431*6777b538SAndroid Build Coastguard Worker // If we don't have a backend, when its construction finishes it will
432*6777b538SAndroid Build Coastguard Worker // deliver the callbacks.
433*6777b538SAndroid Build Coastguard Worker delete_pending_op = false;
434*6777b538SAndroid Build Coastguard Worker }
435*6777b538SAndroid Build Coastguard Worker
436*6777b538SAndroid Build Coastguard Worker pending_op->pending_queue.clear();
437*6777b538SAndroid Build Coastguard Worker if (delete_pending_op) {
438*6777b538SAndroid Build Coastguard Worker delete pending_op;
439*6777b538SAndroid Build Coastguard Worker }
440*6777b538SAndroid Build Coastguard Worker }
441*6777b538SAndroid Build Coastguard Worker }
442*6777b538SAndroid Build Coastguard Worker
GetBackend(disk_cache::Backend ** backend,CompletionOnceCallback callback)443*6777b538SAndroid Build Coastguard Worker int HttpCache::GetBackend(disk_cache::Backend** backend,
444*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback) {
445*6777b538SAndroid Build Coastguard Worker DCHECK(!callback.is_null());
446*6777b538SAndroid Build Coastguard Worker
447*6777b538SAndroid Build Coastguard Worker if (disk_cache_.get()) {
448*6777b538SAndroid Build Coastguard Worker *backend = disk_cache_.get();
449*6777b538SAndroid Build Coastguard Worker return OK;
450*6777b538SAndroid Build Coastguard Worker }
451*6777b538SAndroid Build Coastguard Worker
452*6777b538SAndroid Build Coastguard Worker int rv =
453*6777b538SAndroid Build Coastguard Worker CreateBackend(base::BindOnce(&HttpCache::ReportGetBackendResult,
454*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), backend, std::move(callback)));
455*6777b538SAndroid Build Coastguard Worker if (rv != net::ERR_IO_PENDING) {
456*6777b538SAndroid Build Coastguard Worker *backend = disk_cache_.get();
457*6777b538SAndroid Build Coastguard Worker }
458*6777b538SAndroid Build Coastguard Worker return rv;
459*6777b538SAndroid Build Coastguard Worker }
460*6777b538SAndroid Build Coastguard Worker
ReportGetBackendResult(disk_cache::Backend ** backend,CompletionOnceCallback callback,int net_error)461*6777b538SAndroid Build Coastguard Worker void HttpCache::ReportGetBackendResult(disk_cache::Backend** backend,
462*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback,
463*6777b538SAndroid Build Coastguard Worker int net_error) {
464*6777b538SAndroid Build Coastguard Worker *backend = disk_cache_.get();
465*6777b538SAndroid Build Coastguard Worker std::move(callback).Run(net_error);
466*6777b538SAndroid Build Coastguard Worker }
467*6777b538SAndroid Build Coastguard Worker
GetCurrentBackend() const468*6777b538SAndroid Build Coastguard Worker disk_cache::Backend* HttpCache::GetCurrentBackend() const {
469*6777b538SAndroid Build Coastguard Worker return disk_cache_.get();
470*6777b538SAndroid Build Coastguard Worker }
471*6777b538SAndroid Build Coastguard Worker
472*6777b538SAndroid Build Coastguard Worker // static
ParseResponseInfo(const char * data,int len,HttpResponseInfo * response_info,bool * response_truncated)473*6777b538SAndroid Build Coastguard Worker bool HttpCache::ParseResponseInfo(const char* data,
474*6777b538SAndroid Build Coastguard Worker int len,
475*6777b538SAndroid Build Coastguard Worker HttpResponseInfo* response_info,
476*6777b538SAndroid Build Coastguard Worker bool* response_truncated) {
477*6777b538SAndroid Build Coastguard Worker base::Pickle pickle = base::Pickle::WithUnownedBuffer(
478*6777b538SAndroid Build Coastguard Worker base::as_bytes(base::span(data, base::checked_cast<size_t>(len))));
479*6777b538SAndroid Build Coastguard Worker return response_info->InitFromPickle(pickle, response_truncated);
480*6777b538SAndroid Build Coastguard Worker }
481*6777b538SAndroid Build Coastguard Worker
CloseAllConnections(int net_error,const char * net_log_reason_utf8)482*6777b538SAndroid Build Coastguard Worker void HttpCache::CloseAllConnections(int net_error,
483*6777b538SAndroid Build Coastguard Worker const char* net_log_reason_utf8) {
484*6777b538SAndroid Build Coastguard Worker HttpNetworkSession* session = GetSession();
485*6777b538SAndroid Build Coastguard Worker if (session) {
486*6777b538SAndroid Build Coastguard Worker session->CloseAllConnections(net_error, net_log_reason_utf8);
487*6777b538SAndroid Build Coastguard Worker }
488*6777b538SAndroid Build Coastguard Worker }
489*6777b538SAndroid Build Coastguard Worker
CloseIdleConnections(const char * net_log_reason_utf8)490*6777b538SAndroid Build Coastguard Worker void HttpCache::CloseIdleConnections(const char* net_log_reason_utf8) {
491*6777b538SAndroid Build Coastguard Worker HttpNetworkSession* session = GetSession();
492*6777b538SAndroid Build Coastguard Worker if (session) {
493*6777b538SAndroid Build Coastguard Worker session->CloseIdleConnections(net_log_reason_utf8);
494*6777b538SAndroid Build Coastguard Worker }
495*6777b538SAndroid Build Coastguard Worker }
496*6777b538SAndroid Build Coastguard Worker
OnExternalCacheHit(const GURL & url,const std::string & http_method,const NetworkIsolationKey & network_isolation_key,bool is_subframe_document_resource,bool used_credentials)497*6777b538SAndroid Build Coastguard Worker void HttpCache::OnExternalCacheHit(
498*6777b538SAndroid Build Coastguard Worker const GURL& url,
499*6777b538SAndroid Build Coastguard Worker const std::string& http_method,
500*6777b538SAndroid Build Coastguard Worker const NetworkIsolationKey& network_isolation_key,
501*6777b538SAndroid Build Coastguard Worker bool is_subframe_document_resource,
502*6777b538SAndroid Build Coastguard Worker bool used_credentials) {
503*6777b538SAndroid Build Coastguard Worker if (!disk_cache_.get() || mode_ == DISABLE) {
504*6777b538SAndroid Build Coastguard Worker return;
505*6777b538SAndroid Build Coastguard Worker }
506*6777b538SAndroid Build Coastguard Worker
507*6777b538SAndroid Build Coastguard Worker if (IsSplitCacheEnabled() && network_isolation_key.IsTransient()) {
508*6777b538SAndroid Build Coastguard Worker return;
509*6777b538SAndroid Build Coastguard Worker }
510*6777b538SAndroid Build Coastguard Worker
511*6777b538SAndroid Build Coastguard Worker HttpRequestInfo request_info;
512*6777b538SAndroid Build Coastguard Worker request_info.url = url;
513*6777b538SAndroid Build Coastguard Worker request_info.method = http_method;
514*6777b538SAndroid Build Coastguard Worker request_info.network_isolation_key = network_isolation_key;
515*6777b538SAndroid Build Coastguard Worker request_info.network_anonymization_key =
516*6777b538SAndroid Build Coastguard Worker net::NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
517*6777b538SAndroid Build Coastguard Worker network_isolation_key);
518*6777b538SAndroid Build Coastguard Worker
519*6777b538SAndroid Build Coastguard Worker request_info.is_subframe_document_resource = is_subframe_document_resource;
520*6777b538SAndroid Build Coastguard Worker if (base::FeatureList::IsEnabled(features::kSplitCacheByIncludeCredentials)) {
521*6777b538SAndroid Build Coastguard Worker if (!used_credentials) {
522*6777b538SAndroid Build Coastguard Worker request_info.load_flags &= LOAD_DO_NOT_SAVE_COOKIES;
523*6777b538SAndroid Build Coastguard Worker } else {
524*6777b538SAndroid Build Coastguard Worker request_info.load_flags |= ~LOAD_DO_NOT_SAVE_COOKIES;
525*6777b538SAndroid Build Coastguard Worker }
526*6777b538SAndroid Build Coastguard Worker }
527*6777b538SAndroid Build Coastguard Worker
528*6777b538SAndroid Build Coastguard Worker std::string key = *GenerateCacheKeyForRequest(&request_info);
529*6777b538SAndroid Build Coastguard Worker disk_cache_->OnExternalCacheHit(key);
530*6777b538SAndroid Build Coastguard Worker }
531*6777b538SAndroid Build Coastguard Worker
CreateTransaction(RequestPriority priority,std::unique_ptr<HttpTransaction> * transaction)532*6777b538SAndroid Build Coastguard Worker int HttpCache::CreateTransaction(
533*6777b538SAndroid Build Coastguard Worker RequestPriority priority,
534*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HttpTransaction>* transaction) {
535*6777b538SAndroid Build Coastguard Worker // Do lazy initialization of disk cache if needed.
536*6777b538SAndroid Build Coastguard Worker if (!disk_cache_.get()) {
537*6777b538SAndroid Build Coastguard Worker // We don't care about the result.
538*6777b538SAndroid Build Coastguard Worker CreateBackend(CompletionOnceCallback());
539*6777b538SAndroid Build Coastguard Worker }
540*6777b538SAndroid Build Coastguard Worker
541*6777b538SAndroid Build Coastguard Worker auto new_transaction =
542*6777b538SAndroid Build Coastguard Worker std::make_unique<HttpCache::Transaction>(priority, this);
543*6777b538SAndroid Build Coastguard Worker if (bypass_lock_for_test_) {
544*6777b538SAndroid Build Coastguard Worker new_transaction->BypassLockForTest();
545*6777b538SAndroid Build Coastguard Worker }
546*6777b538SAndroid Build Coastguard Worker if (bypass_lock_after_headers_for_test_) {
547*6777b538SAndroid Build Coastguard Worker new_transaction->BypassLockAfterHeadersForTest();
548*6777b538SAndroid Build Coastguard Worker }
549*6777b538SAndroid Build Coastguard Worker if (fail_conditionalization_for_test_) {
550*6777b538SAndroid Build Coastguard Worker new_transaction->FailConditionalizationForTest();
551*6777b538SAndroid Build Coastguard Worker }
552*6777b538SAndroid Build Coastguard Worker
553*6777b538SAndroid Build Coastguard Worker *transaction = std::move(new_transaction);
554*6777b538SAndroid Build Coastguard Worker return OK;
555*6777b538SAndroid Build Coastguard Worker }
556*6777b538SAndroid Build Coastguard Worker
GetCache()557*6777b538SAndroid Build Coastguard Worker HttpCache* HttpCache::GetCache() {
558*6777b538SAndroid Build Coastguard Worker return this;
559*6777b538SAndroid Build Coastguard Worker }
560*6777b538SAndroid Build Coastguard Worker
GetSession()561*6777b538SAndroid Build Coastguard Worker HttpNetworkSession* HttpCache::GetSession() {
562*6777b538SAndroid Build Coastguard Worker return network_layer_->GetSession();
563*6777b538SAndroid Build Coastguard Worker }
564*6777b538SAndroid Build Coastguard Worker
565*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HttpTransactionFactory>
SetHttpNetworkTransactionFactoryForTesting(std::unique_ptr<HttpTransactionFactory> new_network_layer)566*6777b538SAndroid Build Coastguard Worker HttpCache::SetHttpNetworkTransactionFactoryForTesting(
567*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HttpTransactionFactory> new_network_layer) {
568*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HttpTransactionFactory> old_network_layer(
569*6777b538SAndroid Build Coastguard Worker std::move(network_layer_));
570*6777b538SAndroid Build Coastguard Worker network_layer_ = std::move(new_network_layer);
571*6777b538SAndroid Build Coastguard Worker return old_network_layer;
572*6777b538SAndroid Build Coastguard Worker }
573*6777b538SAndroid Build Coastguard Worker
574*6777b538SAndroid Build Coastguard Worker // static
GetResourceURLFromHttpCacheKey(const std::string & key)575*6777b538SAndroid Build Coastguard Worker std::string HttpCache::GetResourceURLFromHttpCacheKey(const std::string& key) {
576*6777b538SAndroid Build Coastguard Worker // The key format is:
577*6777b538SAndroid Build Coastguard Worker // credential_key/post_key/[isolation_key]url
578*6777b538SAndroid Build Coastguard Worker
579*6777b538SAndroid Build Coastguard Worker std::string::size_type pos = 0;
580*6777b538SAndroid Build Coastguard Worker pos = key.find('/', pos) + 1; // Consume credential_key/
581*6777b538SAndroid Build Coastguard Worker pos = key.find('/', pos) + 1; // Consume post_key/
582*6777b538SAndroid Build Coastguard Worker
583*6777b538SAndroid Build Coastguard Worker // It is a good idea to make this function tolerate invalid input. This can
584*6777b538SAndroid Build Coastguard Worker // happen because of disk corruption.
585*6777b538SAndroid Build Coastguard Worker if (pos == std::string::npos) {
586*6777b538SAndroid Build Coastguard Worker return "";
587*6777b538SAndroid Build Coastguard Worker }
588*6777b538SAndroid Build Coastguard Worker
589*6777b538SAndroid Build Coastguard Worker // Consume [isolation_key].
590*6777b538SAndroid Build Coastguard Worker // Search the key to see whether it begins with |kDoubleKeyPrefix|. If so,
591*6777b538SAndroid Build Coastguard Worker // then the entry was double-keyed.
592*6777b538SAndroid Build Coastguard Worker if (pos == key.find(kDoubleKeyPrefix, pos)) {
593*6777b538SAndroid Build Coastguard Worker // Find the rightmost occurrence of |kDoubleKeySeparator|, as when both
594*6777b538SAndroid Build Coastguard Worker // the top-frame origin and the initiator are added to the key, there will
595*6777b538SAndroid Build Coastguard Worker // be two occurrences of |kDoubleKeySeparator|. When the cache entry is
596*6777b538SAndroid Build Coastguard Worker // originally written to disk, GenerateCacheKey method calls
597*6777b538SAndroid Build Coastguard Worker // HttpUtil::SpecForRequest method, which has a DCHECK to ensure that
598*6777b538SAndroid Build Coastguard Worker // the original resource url is valid, and hence will not contain the
599*6777b538SAndroid Build Coastguard Worker // unescaped whitespace of |kDoubleKeySeparator|.
600*6777b538SAndroid Build Coastguard Worker pos = key.rfind(kDoubleKeySeparator);
601*6777b538SAndroid Build Coastguard Worker DCHECK_NE(pos, std::string::npos);
602*6777b538SAndroid Build Coastguard Worker pos += strlen(kDoubleKeySeparator);
603*6777b538SAndroid Build Coastguard Worker DCHECK_LE(pos, key.size() - 1);
604*6777b538SAndroid Build Coastguard Worker }
605*6777b538SAndroid Build Coastguard Worker return key.substr(pos);
606*6777b538SAndroid Build Coastguard Worker }
607*6777b538SAndroid Build Coastguard Worker
608*6777b538SAndroid Build Coastguard Worker // static
609*6777b538SAndroid Build Coastguard Worker // Generate a key that can be used inside the cache.
GenerateCacheKey(const GURL & url,int load_flags,const NetworkIsolationKey & network_isolation_key,int64_t upload_data_identifier,bool is_subframe_document_resource)610*6777b538SAndroid Build Coastguard Worker std::optional<std::string> HttpCache::GenerateCacheKey(
611*6777b538SAndroid Build Coastguard Worker const GURL& url,
612*6777b538SAndroid Build Coastguard Worker int load_flags,
613*6777b538SAndroid Build Coastguard Worker const NetworkIsolationKey& network_isolation_key,
614*6777b538SAndroid Build Coastguard Worker int64_t upload_data_identifier,
615*6777b538SAndroid Build Coastguard Worker bool is_subframe_document_resource) {
616*6777b538SAndroid Build Coastguard Worker // The first character of the key may vary depending on whether or not sending
617*6777b538SAndroid Build Coastguard Worker // credentials is permitted for this request. This only happens if the
618*6777b538SAndroid Build Coastguard Worker // SplitCacheByIncludeCredentials feature is enabled.
619*6777b538SAndroid Build Coastguard Worker const char credential_key = (base::FeatureList::IsEnabled(
620*6777b538SAndroid Build Coastguard Worker features::kSplitCacheByIncludeCredentials) &&
621*6777b538SAndroid Build Coastguard Worker (load_flags & LOAD_DO_NOT_SAVE_COOKIES))
622*6777b538SAndroid Build Coastguard Worker ? '0'
623*6777b538SAndroid Build Coastguard Worker : '1';
624*6777b538SAndroid Build Coastguard Worker
625*6777b538SAndroid Build Coastguard Worker std::string isolation_key;
626*6777b538SAndroid Build Coastguard Worker if (IsSplitCacheEnabled()) {
627*6777b538SAndroid Build Coastguard Worker // Prepend the key with |kDoubleKeyPrefix| = "_dk_" to mark it as
628*6777b538SAndroid Build Coastguard Worker // double-keyed (and makes it an invalid url so that it doesn't get
629*6777b538SAndroid Build Coastguard Worker // confused with a single-keyed entry). Separate the origin and url
630*6777b538SAndroid Build Coastguard Worker // with invalid whitespace character |kDoubleKeySeparator|.
631*6777b538SAndroid Build Coastguard Worker if (network_isolation_key.IsTransient()) {
632*6777b538SAndroid Build Coastguard Worker return std::nullopt;
633*6777b538SAndroid Build Coastguard Worker }
634*6777b538SAndroid Build Coastguard Worker std::string subframe_document_resource_prefix =
635*6777b538SAndroid Build Coastguard Worker is_subframe_document_resource ? kSubframeDocumentResourcePrefix : "";
636*6777b538SAndroid Build Coastguard Worker isolation_key = base::StrCat(
637*6777b538SAndroid Build Coastguard Worker {kDoubleKeyPrefix, subframe_document_resource_prefix,
638*6777b538SAndroid Build Coastguard Worker *network_isolation_key.ToCacheKeyString(), kDoubleKeySeparator});
639*6777b538SAndroid Build Coastguard Worker }
640*6777b538SAndroid Build Coastguard Worker
641*6777b538SAndroid Build Coastguard Worker // The key format is:
642*6777b538SAndroid Build Coastguard Worker // credential_key/upload_data_identifier/[isolation_key]url
643*6777b538SAndroid Build Coastguard Worker
644*6777b538SAndroid Build Coastguard Worker // Strip out the reference, username, and password sections of the URL and
645*6777b538SAndroid Build Coastguard Worker // concatenate with the credential_key, the post_key, and the network
646*6777b538SAndroid Build Coastguard Worker // isolation key if we are splitting the cache.
647*6777b538SAndroid Build Coastguard Worker return base::StringPrintf("%c/%" PRId64 "/%s%s", credential_key,
648*6777b538SAndroid Build Coastguard Worker upload_data_identifier, isolation_key.c_str(),
649*6777b538SAndroid Build Coastguard Worker HttpUtil::SpecForRequest(url).c_str());
650*6777b538SAndroid Build Coastguard Worker }
651*6777b538SAndroid Build Coastguard Worker
652*6777b538SAndroid Build Coastguard Worker // static
GenerateCacheKeyForRequest(const HttpRequestInfo * request)653*6777b538SAndroid Build Coastguard Worker std::optional<std::string> HttpCache::GenerateCacheKeyForRequest(
654*6777b538SAndroid Build Coastguard Worker const HttpRequestInfo* request) {
655*6777b538SAndroid Build Coastguard Worker CHECK(request);
656*6777b538SAndroid Build Coastguard Worker const int64_t upload_data_identifier =
657*6777b538SAndroid Build Coastguard Worker request->upload_data_stream ? request->upload_data_stream->identifier()
658*6777b538SAndroid Build Coastguard Worker : int64_t(0);
659*6777b538SAndroid Build Coastguard Worker return GenerateCacheKey(
660*6777b538SAndroid Build Coastguard Worker request->url, request->load_flags, request->network_isolation_key,
661*6777b538SAndroid Build Coastguard Worker upload_data_identifier, request->is_subframe_document_resource);
662*6777b538SAndroid Build Coastguard Worker }
663*6777b538SAndroid Build Coastguard Worker
664*6777b538SAndroid Build Coastguard Worker // static
SplitCacheFeatureEnableByDefault()665*6777b538SAndroid Build Coastguard Worker void HttpCache::SplitCacheFeatureEnableByDefault() {
666*6777b538SAndroid Build Coastguard Worker CHECK(!g_enable_split_cache && !g_init_cache);
667*6777b538SAndroid Build Coastguard Worker if (!base::FeatureList::GetInstance()->IsFeatureOverridden(
668*6777b538SAndroid Build Coastguard Worker "SplitCacheByNetworkIsolationKey")) {
669*6777b538SAndroid Build Coastguard Worker g_enable_split_cache = true;
670*6777b538SAndroid Build Coastguard Worker }
671*6777b538SAndroid Build Coastguard Worker }
672*6777b538SAndroid Build Coastguard Worker
673*6777b538SAndroid Build Coastguard Worker // static
IsSplitCacheEnabled()674*6777b538SAndroid Build Coastguard Worker bool HttpCache::IsSplitCacheEnabled() {
675*6777b538SAndroid Build Coastguard Worker return base::FeatureList::IsEnabled(
676*6777b538SAndroid Build Coastguard Worker features::kSplitCacheByNetworkIsolationKey) ||
677*6777b538SAndroid Build Coastguard Worker g_enable_split_cache;
678*6777b538SAndroid Build Coastguard Worker }
679*6777b538SAndroid Build Coastguard Worker
680*6777b538SAndroid Build Coastguard Worker // static
ClearGlobalsForTesting()681*6777b538SAndroid Build Coastguard Worker void HttpCache::ClearGlobalsForTesting() {
682*6777b538SAndroid Build Coastguard Worker // Reset these so that unit tests can work.
683*6777b538SAndroid Build Coastguard Worker g_init_cache = false;
684*6777b538SAndroid Build Coastguard Worker g_enable_split_cache = false;
685*6777b538SAndroid Build Coastguard Worker }
686*6777b538SAndroid Build Coastguard Worker
687*6777b538SAndroid Build Coastguard Worker //-----------------------------------------------------------------------------
688*6777b538SAndroid Build Coastguard Worker
CreateAndSetWorkItem(scoped_refptr<ActiveEntry> * entry,Transaction * transaction,WorkItemOperation operation,PendingOp * pending_op)689*6777b538SAndroid Build Coastguard Worker net::Error HttpCache::CreateAndSetWorkItem(scoped_refptr<ActiveEntry>* entry,
690*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
691*6777b538SAndroid Build Coastguard Worker WorkItemOperation operation,
692*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op) {
693*6777b538SAndroid Build Coastguard Worker auto item = std::make_unique<WorkItem>(operation, transaction, entry);
694*6777b538SAndroid Build Coastguard Worker
695*6777b538SAndroid Build Coastguard Worker if (pending_op->writer) {
696*6777b538SAndroid Build Coastguard Worker pending_op->pending_queue.push_back(std::move(item));
697*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
698*6777b538SAndroid Build Coastguard Worker }
699*6777b538SAndroid Build Coastguard Worker
700*6777b538SAndroid Build Coastguard Worker DCHECK(pending_op->pending_queue.empty());
701*6777b538SAndroid Build Coastguard Worker
702*6777b538SAndroid Build Coastguard Worker pending_op->writer = std::move(item);
703*6777b538SAndroid Build Coastguard Worker return OK;
704*6777b538SAndroid Build Coastguard Worker }
705*6777b538SAndroid Build Coastguard Worker
CreateBackend(CompletionOnceCallback callback)706*6777b538SAndroid Build Coastguard Worker int HttpCache::CreateBackend(CompletionOnceCallback callback) {
707*6777b538SAndroid Build Coastguard Worker DCHECK(!disk_cache_);
708*6777b538SAndroid Build Coastguard Worker
709*6777b538SAndroid Build Coastguard Worker if (!backend_factory_.get()) {
710*6777b538SAndroid Build Coastguard Worker return ERR_FAILED;
711*6777b538SAndroid Build Coastguard Worker }
712*6777b538SAndroid Build Coastguard Worker
713*6777b538SAndroid Build Coastguard Worker building_backend_ = true;
714*6777b538SAndroid Build Coastguard Worker
715*6777b538SAndroid Build Coastguard Worker const bool callback_is_null = callback.is_null();
716*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WorkItem> item = std::make_unique<WorkItem>(
717*6777b538SAndroid Build Coastguard Worker WI_CREATE_BACKEND, nullptr, std::move(callback));
718*6777b538SAndroid Build Coastguard Worker
719*6777b538SAndroid Build Coastguard Worker // This is the only operation that we can do that is not related to any given
720*6777b538SAndroid Build Coastguard Worker // entry, so we use an empty key for it.
721*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = GetPendingOp(std::string());
722*6777b538SAndroid Build Coastguard Worker if (pending_op->writer) {
723*6777b538SAndroid Build Coastguard Worker if (!callback_is_null) {
724*6777b538SAndroid Build Coastguard Worker pending_op->pending_queue.push_back(std::move(item));
725*6777b538SAndroid Build Coastguard Worker }
726*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
727*6777b538SAndroid Build Coastguard Worker }
728*6777b538SAndroid Build Coastguard Worker
729*6777b538SAndroid Build Coastguard Worker DCHECK(pending_op->pending_queue.empty());
730*6777b538SAndroid Build Coastguard Worker
731*6777b538SAndroid Build Coastguard Worker pending_op->writer = std::move(item);
732*6777b538SAndroid Build Coastguard Worker
733*6777b538SAndroid Build Coastguard Worker disk_cache::BackendResult result = backend_factory_->CreateBackend(
734*6777b538SAndroid Build Coastguard Worker net_log_, base::BindOnce(&HttpCache::OnPendingBackendCreationOpComplete,
735*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), pending_op));
736*6777b538SAndroid Build Coastguard Worker if (result.net_error == ERR_IO_PENDING) {
737*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = true;
738*6777b538SAndroid Build Coastguard Worker return result.net_error;
739*6777b538SAndroid Build Coastguard Worker }
740*6777b538SAndroid Build Coastguard Worker
741*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearCallback();
742*6777b538SAndroid Build Coastguard Worker int rv = result.net_error;
743*6777b538SAndroid Build Coastguard Worker OnPendingBackendCreationOpComplete(GetWeakPtr(), pending_op,
744*6777b538SAndroid Build Coastguard Worker std::move(result));
745*6777b538SAndroid Build Coastguard Worker return rv;
746*6777b538SAndroid Build Coastguard Worker }
747*6777b538SAndroid Build Coastguard Worker
GetBackendForTransaction(Transaction * transaction)748*6777b538SAndroid Build Coastguard Worker int HttpCache::GetBackendForTransaction(Transaction* transaction) {
749*6777b538SAndroid Build Coastguard Worker if (disk_cache_.get()) {
750*6777b538SAndroid Build Coastguard Worker return OK;
751*6777b538SAndroid Build Coastguard Worker }
752*6777b538SAndroid Build Coastguard Worker
753*6777b538SAndroid Build Coastguard Worker if (!building_backend_) {
754*6777b538SAndroid Build Coastguard Worker return ERR_FAILED;
755*6777b538SAndroid Build Coastguard Worker }
756*6777b538SAndroid Build Coastguard Worker
757*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WorkItem> item = std::make_unique<WorkItem>(
758*6777b538SAndroid Build Coastguard Worker WI_CREATE_BACKEND, transaction, CompletionOnceCallback());
759*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = GetPendingOp(std::string());
760*6777b538SAndroid Build Coastguard Worker DCHECK(pending_op->writer);
761*6777b538SAndroid Build Coastguard Worker pending_op->pending_queue.push_back(std::move(item));
762*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
763*6777b538SAndroid Build Coastguard Worker }
764*6777b538SAndroid Build Coastguard Worker
DoomActiveEntry(const std::string & key)765*6777b538SAndroid Build Coastguard Worker void HttpCache::DoomActiveEntry(const std::string& key) {
766*6777b538SAndroid Build Coastguard Worker auto it = active_entries_.find(key);
767*6777b538SAndroid Build Coastguard Worker if (it == active_entries_.end()) {
768*6777b538SAndroid Build Coastguard Worker return;
769*6777b538SAndroid Build Coastguard Worker }
770*6777b538SAndroid Build Coastguard Worker
771*6777b538SAndroid Build Coastguard Worker // This is not a performance critical operation, this is handling an error
772*6777b538SAndroid Build Coastguard Worker // condition so it is OK to look up the entry again.
773*6777b538SAndroid Build Coastguard Worker int rv = DoomEntry(key, nullptr);
774*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(OK, rv);
775*6777b538SAndroid Build Coastguard Worker }
776*6777b538SAndroid Build Coastguard Worker
DoomEntry(const std::string & key,Transaction * transaction)777*6777b538SAndroid Build Coastguard Worker int HttpCache::DoomEntry(const std::string& key, Transaction* transaction) {
778*6777b538SAndroid Build Coastguard Worker // Need to abandon the ActiveEntry, but any transaction attached to the entry
779*6777b538SAndroid Build Coastguard Worker // should not be impacted. Dooming an entry only means that it will no longer
780*6777b538SAndroid Build Coastguard Worker // be returned by GetActiveEntry (and it will also be destroyed once all
781*6777b538SAndroid Build Coastguard Worker // consumers are finished with the entry).
782*6777b538SAndroid Build Coastguard Worker auto it = active_entries_.find(key);
783*6777b538SAndroid Build Coastguard Worker if (it == active_entries_.end()) {
784*6777b538SAndroid Build Coastguard Worker DCHECK(transaction);
785*6777b538SAndroid Build Coastguard Worker return AsyncDoomEntry(key, transaction);
786*6777b538SAndroid Build Coastguard Worker }
787*6777b538SAndroid Build Coastguard Worker
788*6777b538SAndroid Build Coastguard Worker raw_ref<ActiveEntry> entry_ref = std::move(it->second);
789*6777b538SAndroid Build Coastguard Worker active_entries_.erase(it);
790*6777b538SAndroid Build Coastguard Worker
791*6777b538SAndroid Build Coastguard Worker // We keep track of doomed entries so that we can ensure that they are
792*6777b538SAndroid Build Coastguard Worker // cleaned up properly when the cache is destroyed.
793*6777b538SAndroid Build Coastguard Worker ActiveEntry& entry = entry_ref.get();
794*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0u, doomed_entries_.count(entry_ref));
795*6777b538SAndroid Build Coastguard Worker doomed_entries_.insert(std::move(entry_ref));
796*6777b538SAndroid Build Coastguard Worker
797*6777b538SAndroid Build Coastguard Worker entry.Doom();
798*6777b538SAndroid Build Coastguard Worker
799*6777b538SAndroid Build Coastguard Worker return OK;
800*6777b538SAndroid Build Coastguard Worker }
801*6777b538SAndroid Build Coastguard Worker
AsyncDoomEntry(const std::string & key,Transaction * transaction)802*6777b538SAndroid Build Coastguard Worker int HttpCache::AsyncDoomEntry(const std::string& key,
803*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
804*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = GetPendingOp(key);
805*6777b538SAndroid Build Coastguard Worker int rv =
806*6777b538SAndroid Build Coastguard Worker CreateAndSetWorkItem(nullptr, transaction, WI_DOOM_ENTRY, pending_op);
807*6777b538SAndroid Build Coastguard Worker if (rv != OK) {
808*6777b538SAndroid Build Coastguard Worker return rv;
809*6777b538SAndroid Build Coastguard Worker }
810*6777b538SAndroid Build Coastguard Worker
811*6777b538SAndroid Build Coastguard Worker net::RequestPriority priority =
812*6777b538SAndroid Build Coastguard Worker transaction ? transaction->priority() : net::LOWEST;
813*6777b538SAndroid Build Coastguard Worker rv = disk_cache_->DoomEntry(key, priority,
814*6777b538SAndroid Build Coastguard Worker base::BindOnce(&HttpCache::OnPendingOpComplete,
815*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), pending_op));
816*6777b538SAndroid Build Coastguard Worker if (rv == ERR_IO_PENDING) {
817*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = true;
818*6777b538SAndroid Build Coastguard Worker return rv;
819*6777b538SAndroid Build Coastguard Worker }
820*6777b538SAndroid Build Coastguard Worker
821*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearTransaction();
822*6777b538SAndroid Build Coastguard Worker OnPendingOpComplete(GetWeakPtr(), pending_op, rv);
823*6777b538SAndroid Build Coastguard Worker return rv;
824*6777b538SAndroid Build Coastguard Worker }
825*6777b538SAndroid Build Coastguard Worker
DoomMainEntryForUrl(const GURL & url,const NetworkIsolationKey & isolation_key,bool is_subframe_document_resource)826*6777b538SAndroid Build Coastguard Worker void HttpCache::DoomMainEntryForUrl(const GURL& url,
827*6777b538SAndroid Build Coastguard Worker const NetworkIsolationKey& isolation_key,
828*6777b538SAndroid Build Coastguard Worker bool is_subframe_document_resource) {
829*6777b538SAndroid Build Coastguard Worker if (!disk_cache_) {
830*6777b538SAndroid Build Coastguard Worker return;
831*6777b538SAndroid Build Coastguard Worker }
832*6777b538SAndroid Build Coastguard Worker
833*6777b538SAndroid Build Coastguard Worker if (IsSplitCacheEnabled() && isolation_key.IsTransient()) {
834*6777b538SAndroid Build Coastguard Worker return;
835*6777b538SAndroid Build Coastguard Worker }
836*6777b538SAndroid Build Coastguard Worker
837*6777b538SAndroid Build Coastguard Worker HttpRequestInfo temp_info;
838*6777b538SAndroid Build Coastguard Worker temp_info.url = url;
839*6777b538SAndroid Build Coastguard Worker temp_info.method = "GET";
840*6777b538SAndroid Build Coastguard Worker temp_info.network_isolation_key = isolation_key;
841*6777b538SAndroid Build Coastguard Worker temp_info.network_anonymization_key =
842*6777b538SAndroid Build Coastguard Worker net::NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
843*6777b538SAndroid Build Coastguard Worker isolation_key);
844*6777b538SAndroid Build Coastguard Worker temp_info.is_subframe_document_resource = is_subframe_document_resource;
845*6777b538SAndroid Build Coastguard Worker std::string key = *GenerateCacheKeyForRequest(&temp_info);
846*6777b538SAndroid Build Coastguard Worker
847*6777b538SAndroid Build Coastguard Worker // Defer to DoomEntry if there is an active entry, otherwise call
848*6777b538SAndroid Build Coastguard Worker // AsyncDoomEntry without triggering a callback.
849*6777b538SAndroid Build Coastguard Worker if (active_entries_.count(key)) {
850*6777b538SAndroid Build Coastguard Worker DoomEntry(key, nullptr);
851*6777b538SAndroid Build Coastguard Worker } else {
852*6777b538SAndroid Build Coastguard Worker AsyncDoomEntry(key, nullptr);
853*6777b538SAndroid Build Coastguard Worker }
854*6777b538SAndroid Build Coastguard Worker }
855*6777b538SAndroid Build Coastguard Worker
HasActiveEntry(const std::string & key)856*6777b538SAndroid Build Coastguard Worker bool HttpCache::HasActiveEntry(const std::string& key) {
857*6777b538SAndroid Build Coastguard Worker return active_entries_.find(key) != active_entries_.end();
858*6777b538SAndroid Build Coastguard Worker }
859*6777b538SAndroid Build Coastguard Worker
GetActiveEntry(const std::string & key)860*6777b538SAndroid Build Coastguard Worker scoped_refptr<HttpCache::ActiveEntry> HttpCache::GetActiveEntry(
861*6777b538SAndroid Build Coastguard Worker const std::string& key) {
862*6777b538SAndroid Build Coastguard Worker auto it = active_entries_.find(key);
863*6777b538SAndroid Build Coastguard Worker return it != active_entries_.end() ? base::WrapRefCounted(&it->second.get())
864*6777b538SAndroid Build Coastguard Worker : nullptr;
865*6777b538SAndroid Build Coastguard Worker }
866*6777b538SAndroid Build Coastguard Worker
ActivateEntry(disk_cache::Entry * disk_entry,bool opened)867*6777b538SAndroid Build Coastguard Worker scoped_refptr<HttpCache::ActiveEntry> HttpCache::ActivateEntry(
868*6777b538SAndroid Build Coastguard Worker disk_cache::Entry* disk_entry,
869*6777b538SAndroid Build Coastguard Worker bool opened) {
870*6777b538SAndroid Build Coastguard Worker DCHECK(!HasActiveEntry(disk_entry->GetKey()));
871*6777b538SAndroid Build Coastguard Worker return base::MakeRefCounted<ActiveEntry>(weak_factory_.GetWeakPtr(),
872*6777b538SAndroid Build Coastguard Worker disk_entry, opened);
873*6777b538SAndroid Build Coastguard Worker }
874*6777b538SAndroid Build Coastguard Worker
GetPendingOp(const std::string & key)875*6777b538SAndroid Build Coastguard Worker HttpCache::PendingOp* HttpCache::GetPendingOp(const std::string& key) {
876*6777b538SAndroid Build Coastguard Worker DCHECK(!HasActiveEntry(key));
877*6777b538SAndroid Build Coastguard Worker
878*6777b538SAndroid Build Coastguard Worker auto it = pending_ops_.find(key);
879*6777b538SAndroid Build Coastguard Worker if (it != pending_ops_.end()) {
880*6777b538SAndroid Build Coastguard Worker return it->second;
881*6777b538SAndroid Build Coastguard Worker }
882*6777b538SAndroid Build Coastguard Worker
883*6777b538SAndroid Build Coastguard Worker PendingOp* operation = new PendingOp();
884*6777b538SAndroid Build Coastguard Worker pending_ops_[key] = operation;
885*6777b538SAndroid Build Coastguard Worker return operation;
886*6777b538SAndroid Build Coastguard Worker }
887*6777b538SAndroid Build Coastguard Worker
DeletePendingOp(PendingOp * pending_op)888*6777b538SAndroid Build Coastguard Worker void HttpCache::DeletePendingOp(PendingOp* pending_op) {
889*6777b538SAndroid Build Coastguard Worker std::string key;
890*6777b538SAndroid Build Coastguard Worker if (pending_op->entry) {
891*6777b538SAndroid Build Coastguard Worker key = pending_op->entry->GetKey();
892*6777b538SAndroid Build Coastguard Worker }
893*6777b538SAndroid Build Coastguard Worker
894*6777b538SAndroid Build Coastguard Worker if (!key.empty()) {
895*6777b538SAndroid Build Coastguard Worker auto it = pending_ops_.find(key);
896*6777b538SAndroid Build Coastguard Worker DCHECK(it != pending_ops_.end());
897*6777b538SAndroid Build Coastguard Worker pending_ops_.erase(it);
898*6777b538SAndroid Build Coastguard Worker } else {
899*6777b538SAndroid Build Coastguard Worker for (auto it = pending_ops_.begin(); it != pending_ops_.end(); ++it) {
900*6777b538SAndroid Build Coastguard Worker if (it->second == pending_op) {
901*6777b538SAndroid Build Coastguard Worker pending_ops_.erase(it);
902*6777b538SAndroid Build Coastguard Worker break;
903*6777b538SAndroid Build Coastguard Worker }
904*6777b538SAndroid Build Coastguard Worker }
905*6777b538SAndroid Build Coastguard Worker }
906*6777b538SAndroid Build Coastguard Worker DCHECK(pending_op->pending_queue.empty());
907*6777b538SAndroid Build Coastguard Worker
908*6777b538SAndroid Build Coastguard Worker delete pending_op;
909*6777b538SAndroid Build Coastguard Worker }
910*6777b538SAndroid Build Coastguard Worker
OpenOrCreateEntry(const std::string & key,scoped_refptr<ActiveEntry> * entry,Transaction * transaction)911*6777b538SAndroid Build Coastguard Worker int HttpCache::OpenOrCreateEntry(const std::string& key,
912*6777b538SAndroid Build Coastguard Worker scoped_refptr<ActiveEntry>* entry,
913*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
914*6777b538SAndroid Build Coastguard Worker DCHECK(!HasActiveEntry(key));
915*6777b538SAndroid Build Coastguard Worker
916*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = GetPendingOp(key);
917*6777b538SAndroid Build Coastguard Worker int rv = CreateAndSetWorkItem(entry, transaction, WI_OPEN_OR_CREATE_ENTRY,
918*6777b538SAndroid Build Coastguard Worker pending_op);
919*6777b538SAndroid Build Coastguard Worker if (rv != OK) {
920*6777b538SAndroid Build Coastguard Worker return rv;
921*6777b538SAndroid Build Coastguard Worker }
922*6777b538SAndroid Build Coastguard Worker
923*6777b538SAndroid Build Coastguard Worker disk_cache::EntryResult entry_result = disk_cache_->OpenOrCreateEntry(
924*6777b538SAndroid Build Coastguard Worker key, transaction->priority(),
925*6777b538SAndroid Build Coastguard Worker base::BindOnce(&HttpCache::OnPendingCreationOpComplete, GetWeakPtr(),
926*6777b538SAndroid Build Coastguard Worker pending_op));
927*6777b538SAndroid Build Coastguard Worker rv = entry_result.net_error();
928*6777b538SAndroid Build Coastguard Worker if (rv == ERR_IO_PENDING) {
929*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = true;
930*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
931*6777b538SAndroid Build Coastguard Worker }
932*6777b538SAndroid Build Coastguard Worker
933*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearTransaction();
934*6777b538SAndroid Build Coastguard Worker OnPendingCreationOpComplete(GetWeakPtr(), pending_op,
935*6777b538SAndroid Build Coastguard Worker std::move(entry_result));
936*6777b538SAndroid Build Coastguard Worker return rv;
937*6777b538SAndroid Build Coastguard Worker }
938*6777b538SAndroid Build Coastguard Worker
OpenEntry(const std::string & key,scoped_refptr<ActiveEntry> * entry,Transaction * transaction)939*6777b538SAndroid Build Coastguard Worker int HttpCache::OpenEntry(const std::string& key,
940*6777b538SAndroid Build Coastguard Worker scoped_refptr<ActiveEntry>* entry,
941*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
942*6777b538SAndroid Build Coastguard Worker DCHECK(!HasActiveEntry(key));
943*6777b538SAndroid Build Coastguard Worker
944*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = GetPendingOp(key);
945*6777b538SAndroid Build Coastguard Worker int rv = CreateAndSetWorkItem(entry, transaction, WI_OPEN_ENTRY, pending_op);
946*6777b538SAndroid Build Coastguard Worker if (rv != OK) {
947*6777b538SAndroid Build Coastguard Worker return rv;
948*6777b538SAndroid Build Coastguard Worker }
949*6777b538SAndroid Build Coastguard Worker
950*6777b538SAndroid Build Coastguard Worker disk_cache::EntryResult entry_result = disk_cache_->OpenEntry(
951*6777b538SAndroid Build Coastguard Worker key, transaction->priority(),
952*6777b538SAndroid Build Coastguard Worker base::BindOnce(&HttpCache::OnPendingCreationOpComplete, GetWeakPtr(),
953*6777b538SAndroid Build Coastguard Worker pending_op));
954*6777b538SAndroid Build Coastguard Worker rv = entry_result.net_error();
955*6777b538SAndroid Build Coastguard Worker if (rv == ERR_IO_PENDING) {
956*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = true;
957*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
958*6777b538SAndroid Build Coastguard Worker }
959*6777b538SAndroid Build Coastguard Worker
960*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearTransaction();
961*6777b538SAndroid Build Coastguard Worker OnPendingCreationOpComplete(GetWeakPtr(), pending_op,
962*6777b538SAndroid Build Coastguard Worker std::move(entry_result));
963*6777b538SAndroid Build Coastguard Worker return rv;
964*6777b538SAndroid Build Coastguard Worker }
965*6777b538SAndroid Build Coastguard Worker
CreateEntry(const std::string & key,scoped_refptr<ActiveEntry> * entry,Transaction * transaction)966*6777b538SAndroid Build Coastguard Worker int HttpCache::CreateEntry(const std::string& key,
967*6777b538SAndroid Build Coastguard Worker scoped_refptr<ActiveEntry>* entry,
968*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
969*6777b538SAndroid Build Coastguard Worker if (HasActiveEntry(key)) {
970*6777b538SAndroid Build Coastguard Worker return ERR_CACHE_RACE;
971*6777b538SAndroid Build Coastguard Worker }
972*6777b538SAndroid Build Coastguard Worker
973*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op = GetPendingOp(key);
974*6777b538SAndroid Build Coastguard Worker int rv =
975*6777b538SAndroid Build Coastguard Worker CreateAndSetWorkItem(entry, transaction, WI_CREATE_ENTRY, pending_op);
976*6777b538SAndroid Build Coastguard Worker if (rv != OK) {
977*6777b538SAndroid Build Coastguard Worker return rv;
978*6777b538SAndroid Build Coastguard Worker }
979*6777b538SAndroid Build Coastguard Worker
980*6777b538SAndroid Build Coastguard Worker disk_cache::EntryResult entry_result = disk_cache_->CreateEntry(
981*6777b538SAndroid Build Coastguard Worker key, transaction->priority(),
982*6777b538SAndroid Build Coastguard Worker base::BindOnce(&HttpCache::OnPendingCreationOpComplete, GetWeakPtr(),
983*6777b538SAndroid Build Coastguard Worker pending_op));
984*6777b538SAndroid Build Coastguard Worker rv = entry_result.net_error();
985*6777b538SAndroid Build Coastguard Worker if (rv == ERR_IO_PENDING) {
986*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = true;
987*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
988*6777b538SAndroid Build Coastguard Worker }
989*6777b538SAndroid Build Coastguard Worker
990*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearTransaction();
991*6777b538SAndroid Build Coastguard Worker OnPendingCreationOpComplete(GetWeakPtr(), pending_op,
992*6777b538SAndroid Build Coastguard Worker std::move(entry_result));
993*6777b538SAndroid Build Coastguard Worker return rv;
994*6777b538SAndroid Build Coastguard Worker }
995*6777b538SAndroid Build Coastguard Worker
AddTransactionToEntry(scoped_refptr<ActiveEntry> & entry,Transaction * transaction)996*6777b538SAndroid Build Coastguard Worker int HttpCache::AddTransactionToEntry(scoped_refptr<ActiveEntry>& entry,
997*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
998*6777b538SAndroid Build Coastguard Worker DCHECK(entry);
999*6777b538SAndroid Build Coastguard Worker DCHECK(entry->GetEntry());
1000*6777b538SAndroid Build Coastguard Worker // Always add a new transaction to the queue to maintain FIFO order.
1001*6777b538SAndroid Build Coastguard Worker entry->add_to_entry_queue().push_back(transaction);
1002*6777b538SAndroid Build Coastguard Worker // Don't process the transaction if the lock timeout handling is being tested.
1003*6777b538SAndroid Build Coastguard Worker if (!bypass_lock_for_test_) {
1004*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(entry);
1005*6777b538SAndroid Build Coastguard Worker }
1006*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
1007*6777b538SAndroid Build Coastguard Worker }
1008*6777b538SAndroid Build Coastguard Worker
DoneWithResponseHeaders(scoped_refptr<ActiveEntry> & entry,Transaction * transaction,bool is_partial)1009*6777b538SAndroid Build Coastguard Worker int HttpCache::DoneWithResponseHeaders(scoped_refptr<ActiveEntry>& entry,
1010*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
1011*6777b538SAndroid Build Coastguard Worker bool is_partial) {
1012*6777b538SAndroid Build Coastguard Worker // If |transaction| is the current writer, do nothing. This can happen for
1013*6777b538SAndroid Build Coastguard Worker // range requests since they can go back to headers phase after starting to
1014*6777b538SAndroid Build Coastguard Worker // write.
1015*6777b538SAndroid Build Coastguard Worker if (entry->HasWriters() && entry->writers()->HasTransaction(transaction)) {
1016*6777b538SAndroid Build Coastguard Worker DCHECK(is_partial && entry->writers()->GetTransactionsCount() == 1);
1017*6777b538SAndroid Build Coastguard Worker return OK;
1018*6777b538SAndroid Build Coastguard Worker }
1019*6777b538SAndroid Build Coastguard Worker
1020*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(entry->headers_transaction(), transaction);
1021*6777b538SAndroid Build Coastguard Worker
1022*6777b538SAndroid Build Coastguard Worker entry->ClearHeadersTransaction();
1023*6777b538SAndroid Build Coastguard Worker
1024*6777b538SAndroid Build Coastguard Worker // If transaction is responsible for writing the response body, then do not go
1025*6777b538SAndroid Build Coastguard Worker // through done_headers_queue for performance benefit. (Also, in case of
1026*6777b538SAndroid Build Coastguard Worker // writer transaction, the consumer sometimes depend on synchronous behaviour
1027*6777b538SAndroid Build Coastguard Worker // e.g. while computing raw headers size. (crbug.com/711766))
1028*6777b538SAndroid Build Coastguard Worker if ((transaction->mode() & Transaction::WRITE) && !entry->HasWriters() &&
1029*6777b538SAndroid Build Coastguard Worker entry->readers().empty()) {
1030*6777b538SAndroid Build Coastguard Worker entry->AddTransactionToWriters(
1031*6777b538SAndroid Build Coastguard Worker transaction, CanTransactionJoinExistingWriters(transaction));
1032*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(entry);
1033*6777b538SAndroid Build Coastguard Worker return OK;
1034*6777b538SAndroid Build Coastguard Worker }
1035*6777b538SAndroid Build Coastguard Worker
1036*6777b538SAndroid Build Coastguard Worker entry->done_headers_queue().push_back(transaction);
1037*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(entry);
1038*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
1039*6777b538SAndroid Build Coastguard Worker }
1040*6777b538SAndroid Build Coastguard Worker
DoneWithEntry(scoped_refptr<ActiveEntry> & entry,Transaction * transaction,bool entry_is_complete,bool is_partial)1041*6777b538SAndroid Build Coastguard Worker void HttpCache::DoneWithEntry(scoped_refptr<ActiveEntry>& entry,
1042*6777b538SAndroid Build Coastguard Worker Transaction* transaction,
1043*6777b538SAndroid Build Coastguard Worker bool entry_is_complete,
1044*6777b538SAndroid Build Coastguard Worker bool is_partial) {
1045*6777b538SAndroid Build Coastguard Worker bool is_mode_read_only = transaction->mode() == Transaction::READ;
1046*6777b538SAndroid Build Coastguard Worker
1047*6777b538SAndroid Build Coastguard Worker if (!entry_is_complete && !is_mode_read_only && is_partial) {
1048*6777b538SAndroid Build Coastguard Worker entry->GetEntry()->CancelSparseIO();
1049*6777b538SAndroid Build Coastguard Worker }
1050*6777b538SAndroid Build Coastguard Worker
1051*6777b538SAndroid Build Coastguard Worker // Transaction is waiting in the done_headers_queue.
1052*6777b538SAndroid Build Coastguard Worker auto it = base::ranges::find(entry->done_headers_queue(), transaction);
1053*6777b538SAndroid Build Coastguard Worker if (it != entry->done_headers_queue().end()) {
1054*6777b538SAndroid Build Coastguard Worker entry->done_headers_queue().erase(it);
1055*6777b538SAndroid Build Coastguard Worker
1056*6777b538SAndroid Build Coastguard Worker // Restart other transactions if this transaction could have written
1057*6777b538SAndroid Build Coastguard Worker // response body.
1058*6777b538SAndroid Build Coastguard Worker if (!entry_is_complete && !is_mode_read_only) {
1059*6777b538SAndroid Build Coastguard Worker ProcessEntryFailure(entry.get());
1060*6777b538SAndroid Build Coastguard Worker }
1061*6777b538SAndroid Build Coastguard Worker return;
1062*6777b538SAndroid Build Coastguard Worker }
1063*6777b538SAndroid Build Coastguard Worker
1064*6777b538SAndroid Build Coastguard Worker // Transaction is removed in the headers phase.
1065*6777b538SAndroid Build Coastguard Worker if (transaction == entry->headers_transaction()) {
1066*6777b538SAndroid Build Coastguard Worker entry->ClearHeadersTransaction();
1067*6777b538SAndroid Build Coastguard Worker
1068*6777b538SAndroid Build Coastguard Worker if (entry_is_complete || is_mode_read_only) {
1069*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(entry);
1070*6777b538SAndroid Build Coastguard Worker } else {
1071*6777b538SAndroid Build Coastguard Worker // Restart other transactions if this transaction could have written
1072*6777b538SAndroid Build Coastguard Worker // response body.
1073*6777b538SAndroid Build Coastguard Worker ProcessEntryFailure(entry.get());
1074*6777b538SAndroid Build Coastguard Worker }
1075*6777b538SAndroid Build Coastguard Worker return;
1076*6777b538SAndroid Build Coastguard Worker }
1077*6777b538SAndroid Build Coastguard Worker
1078*6777b538SAndroid Build Coastguard Worker // Transaction is removed in the writing phase.
1079*6777b538SAndroid Build Coastguard Worker if (entry->HasWriters() && entry->writers()->HasTransaction(transaction)) {
1080*6777b538SAndroid Build Coastguard Worker entry->writers()->RemoveTransaction(transaction,
1081*6777b538SAndroid Build Coastguard Worker entry_is_complete /* success */);
1082*6777b538SAndroid Build Coastguard Worker return;
1083*6777b538SAndroid Build Coastguard Worker }
1084*6777b538SAndroid Build Coastguard Worker
1085*6777b538SAndroid Build Coastguard Worker // Transaction is reading from the entry.
1086*6777b538SAndroid Build Coastguard Worker DCHECK(!entry->HasWriters());
1087*6777b538SAndroid Build Coastguard Worker auto readers_it = entry->readers().find(transaction);
1088*6777b538SAndroid Build Coastguard Worker DCHECK(readers_it != entry->readers().end());
1089*6777b538SAndroid Build Coastguard Worker entry->readers().erase(readers_it);
1090*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(entry);
1091*6777b538SAndroid Build Coastguard Worker }
1092*6777b538SAndroid Build Coastguard Worker
WritersDoomEntryRestartTransactions(ActiveEntry * entry)1093*6777b538SAndroid Build Coastguard Worker void HttpCache::WritersDoomEntryRestartTransactions(ActiveEntry* entry) {
1094*6777b538SAndroid Build Coastguard Worker DCHECK(!entry->writers()->IsEmpty());
1095*6777b538SAndroid Build Coastguard Worker ProcessEntryFailure(entry);
1096*6777b538SAndroid Build Coastguard Worker }
1097*6777b538SAndroid Build Coastguard Worker
WritersDoneWritingToEntry(scoped_refptr<ActiveEntry> entry,bool success,bool should_keep_entry,TransactionSet make_readers)1098*6777b538SAndroid Build Coastguard Worker void HttpCache::WritersDoneWritingToEntry(scoped_refptr<ActiveEntry> entry,
1099*6777b538SAndroid Build Coastguard Worker bool success,
1100*6777b538SAndroid Build Coastguard Worker bool should_keep_entry,
1101*6777b538SAndroid Build Coastguard Worker TransactionSet make_readers) {
1102*6777b538SAndroid Build Coastguard Worker // Impacts the queued transactions in one of the following ways:
1103*6777b538SAndroid Build Coastguard Worker // - restart them but do not doom the entry since entry can be saved in
1104*6777b538SAndroid Build Coastguard Worker // its truncated form.
1105*6777b538SAndroid Build Coastguard Worker // - restart them and doom/destroy the entry since entry does not
1106*6777b538SAndroid Build Coastguard Worker // have valid contents.
1107*6777b538SAndroid Build Coastguard Worker // - let them continue by invoking their callback since entry is
1108*6777b538SAndroid Build Coastguard Worker // successfully written.
1109*6777b538SAndroid Build Coastguard Worker DCHECK(entry->HasWriters());
1110*6777b538SAndroid Build Coastguard Worker DCHECK(entry->writers()->IsEmpty());
1111*6777b538SAndroid Build Coastguard Worker DCHECK(success || make_readers.empty());
1112*6777b538SAndroid Build Coastguard Worker
1113*6777b538SAndroid Build Coastguard Worker if (!success && should_keep_entry) {
1114*6777b538SAndroid Build Coastguard Worker // Restart already validated transactions so that they are able to read
1115*6777b538SAndroid Build Coastguard Worker // the truncated status of the entry.
1116*6777b538SAndroid Build Coastguard Worker entry->RestartHeadersPhaseTransactions();
1117*6777b538SAndroid Build Coastguard Worker entry->ReleaseWriters();
1118*6777b538SAndroid Build Coastguard Worker return;
1119*6777b538SAndroid Build Coastguard Worker }
1120*6777b538SAndroid Build Coastguard Worker
1121*6777b538SAndroid Build Coastguard Worker if (success) {
1122*6777b538SAndroid Build Coastguard Worker // Add any idle writers to readers.
1123*6777b538SAndroid Build Coastguard Worker for (Transaction* reader : make_readers) {
1124*6777b538SAndroid Build Coastguard Worker reader->WriteModeTransactionAboutToBecomeReader();
1125*6777b538SAndroid Build Coastguard Worker entry->readers().insert(reader);
1126*6777b538SAndroid Build Coastguard Worker }
1127*6777b538SAndroid Build Coastguard Worker // Reset writers here so that WriteModeTransactionAboutToBecomeReader can
1128*6777b538SAndroid Build Coastguard Worker // access the network transaction.
1129*6777b538SAndroid Build Coastguard Worker entry->ReleaseWriters();
1130*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(std::move(entry));
1131*6777b538SAndroid Build Coastguard Worker } else {
1132*6777b538SAndroid Build Coastguard Worker entry->ReleaseWriters();
1133*6777b538SAndroid Build Coastguard Worker ProcessEntryFailure(entry.get());
1134*6777b538SAndroid Build Coastguard Worker }
1135*6777b538SAndroid Build Coastguard Worker }
1136*6777b538SAndroid Build Coastguard Worker
DoomEntryValidationNoMatch(scoped_refptr<ActiveEntry> entry)1137*6777b538SAndroid Build Coastguard Worker void HttpCache::DoomEntryValidationNoMatch(scoped_refptr<ActiveEntry> entry) {
1138*6777b538SAndroid Build Coastguard Worker // Validating transaction received a non-matching response.
1139*6777b538SAndroid Build Coastguard Worker DCHECK(entry->headers_transaction());
1140*6777b538SAndroid Build Coastguard Worker
1141*6777b538SAndroid Build Coastguard Worker entry->ClearHeadersTransaction();
1142*6777b538SAndroid Build Coastguard Worker
1143*6777b538SAndroid Build Coastguard Worker DoomActiveEntry(entry->GetEntry()->GetKey());
1144*6777b538SAndroid Build Coastguard Worker
1145*6777b538SAndroid Build Coastguard Worker // Restart only add_to_entry_queue transactions.
1146*6777b538SAndroid Build Coastguard Worker // Post task here to avoid a race in creating the entry between |transaction|
1147*6777b538SAndroid Build Coastguard Worker // and the add_to_entry_queue transactions. Reset the queued transaction's
1148*6777b538SAndroid Build Coastguard Worker // cache pending state so that in case it's destructor is invoked, it's ok
1149*6777b538SAndroid Build Coastguard Worker // for the transaction to not be found in this entry.
1150*6777b538SAndroid Build Coastguard Worker for (net::HttpCache::Transaction* transaction : entry->add_to_entry_queue()) {
1151*6777b538SAndroid Build Coastguard Worker transaction->ResetCachePendingState();
1152*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1153*6777b538SAndroid Build Coastguard Worker FROM_HERE,
1154*6777b538SAndroid Build Coastguard Worker base::BindOnce(transaction->cache_io_callback(), net::ERR_CACHE_RACE));
1155*6777b538SAndroid Build Coastguard Worker }
1156*6777b538SAndroid Build Coastguard Worker entry->add_to_entry_queue().clear();
1157*6777b538SAndroid Build Coastguard Worker }
1158*6777b538SAndroid Build Coastguard Worker
ProcessEntryFailure(ActiveEntry * entry)1159*6777b538SAndroid Build Coastguard Worker void HttpCache::ProcessEntryFailure(ActiveEntry* entry) {
1160*6777b538SAndroid Build Coastguard Worker // The writer failed to completely write the response to
1161*6777b538SAndroid Build Coastguard Worker // the cache.
1162*6777b538SAndroid Build Coastguard Worker
1163*6777b538SAndroid Build Coastguard Worker if (entry->headers_transaction()) {
1164*6777b538SAndroid Build Coastguard Worker entry->RestartHeadersTransaction();
1165*6777b538SAndroid Build Coastguard Worker }
1166*6777b538SAndroid Build Coastguard Worker
1167*6777b538SAndroid Build Coastguard Worker TransactionList list = entry->TakeAllQueuedTransactions();
1168*6777b538SAndroid Build Coastguard Worker
1169*6777b538SAndroid Build Coastguard Worker DoomActiveEntry(entry->GetEntry()->GetKey());
1170*6777b538SAndroid Build Coastguard Worker
1171*6777b538SAndroid Build Coastguard Worker // ERR_CACHE_RACE causes the transaction to restart the whole process.
1172*6777b538SAndroid Build Coastguard Worker for (Transaction* queued_transaction : list) {
1173*6777b538SAndroid Build Coastguard Worker queued_transaction->cache_io_callback().Run(net::ERR_CACHE_RACE);
1174*6777b538SAndroid Build Coastguard Worker }
1175*6777b538SAndroid Build Coastguard Worker }
1176*6777b538SAndroid Build Coastguard Worker
ProcessQueuedTransactions(scoped_refptr<ActiveEntry> entry)1177*6777b538SAndroid Build Coastguard Worker void HttpCache::ProcessQueuedTransactions(scoped_refptr<ActiveEntry> entry) {
1178*6777b538SAndroid Build Coastguard Worker // Multiple readers may finish with an entry at once, so we want to batch up
1179*6777b538SAndroid Build Coastguard Worker // calls to OnProcessQueuedTransactions. This flag also tells us that we
1180*6777b538SAndroid Build Coastguard Worker // should not delete the entry before OnProcessQueuedTransactions runs.
1181*6777b538SAndroid Build Coastguard Worker if (entry->will_process_queued_transactions()) {
1182*6777b538SAndroid Build Coastguard Worker return;
1183*6777b538SAndroid Build Coastguard Worker }
1184*6777b538SAndroid Build Coastguard Worker
1185*6777b538SAndroid Build Coastguard Worker entry->set_will_process_queued_transactions(true);
1186*6777b538SAndroid Build Coastguard Worker
1187*6777b538SAndroid Build Coastguard Worker // Post a task instead of invoking the io callback of another transaction here
1188*6777b538SAndroid Build Coastguard Worker // to avoid re-entrancy.
1189*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1190*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(&HttpCache::OnProcessQueuedTransactions,
1191*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), std::move(entry)));
1192*6777b538SAndroid Build Coastguard Worker }
1193*6777b538SAndroid Build Coastguard Worker
ProcessAddToEntryQueue(scoped_refptr<ActiveEntry> entry)1194*6777b538SAndroid Build Coastguard Worker void HttpCache::ProcessAddToEntryQueue(scoped_refptr<ActiveEntry> entry) {
1195*6777b538SAndroid Build Coastguard Worker CHECK(!entry->add_to_entry_queue().empty());
1196*6777b538SAndroid Build Coastguard Worker if (delay_add_transaction_to_entry_for_test_) {
1197*6777b538SAndroid Build Coastguard Worker // Post a task to put the AddTransactionToEntry handling at the back of
1198*6777b538SAndroid Build Coastguard Worker // the task queue. This allows other tasks (like network IO) to jump
1199*6777b538SAndroid Build Coastguard Worker // ahead and simulate different callback ordering for testing.
1200*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1201*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(&HttpCache::ProcessAddToEntryQueueImpl,
1202*6777b538SAndroid Build Coastguard Worker GetWeakPtr(), std::move(entry)));
1203*6777b538SAndroid Build Coastguard Worker } else {
1204*6777b538SAndroid Build Coastguard Worker entry->ProcessAddToEntryQueue();
1205*6777b538SAndroid Build Coastguard Worker }
1206*6777b538SAndroid Build Coastguard Worker }
1207*6777b538SAndroid Build Coastguard Worker
ProcessAddToEntryQueueImpl(scoped_refptr<ActiveEntry> entry)1208*6777b538SAndroid Build Coastguard Worker void HttpCache::ProcessAddToEntryQueueImpl(scoped_refptr<ActiveEntry> entry) {
1209*6777b538SAndroid Build Coastguard Worker entry->ProcessAddToEntryQueue();
1210*6777b538SAndroid Build Coastguard Worker }
1211*6777b538SAndroid Build Coastguard Worker
CanTransactionJoinExistingWriters(Transaction * transaction)1212*6777b538SAndroid Build Coastguard Worker HttpCache::ParallelWritingPattern HttpCache::CanTransactionJoinExistingWriters(
1213*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
1214*6777b538SAndroid Build Coastguard Worker if (transaction->method() != "GET") {
1215*6777b538SAndroid Build Coastguard Worker return PARALLEL_WRITING_NOT_JOIN_METHOD_NOT_GET;
1216*6777b538SAndroid Build Coastguard Worker }
1217*6777b538SAndroid Build Coastguard Worker if (transaction->partial()) {
1218*6777b538SAndroid Build Coastguard Worker return PARALLEL_WRITING_NOT_JOIN_RANGE;
1219*6777b538SAndroid Build Coastguard Worker }
1220*6777b538SAndroid Build Coastguard Worker if (transaction->mode() == Transaction::READ) {
1221*6777b538SAndroid Build Coastguard Worker return PARALLEL_WRITING_NOT_JOIN_READ_ONLY;
1222*6777b538SAndroid Build Coastguard Worker }
1223*6777b538SAndroid Build Coastguard Worker if (transaction->GetResponseInfo()->headers &&
1224*6777b538SAndroid Build Coastguard Worker transaction->GetResponseInfo()->headers->GetContentLength() >
1225*6777b538SAndroid Build Coastguard Worker disk_cache_->MaxFileSize()) {
1226*6777b538SAndroid Build Coastguard Worker return PARALLEL_WRITING_NOT_JOIN_TOO_BIG_FOR_CACHE;
1227*6777b538SAndroid Build Coastguard Worker }
1228*6777b538SAndroid Build Coastguard Worker return PARALLEL_WRITING_JOIN;
1229*6777b538SAndroid Build Coastguard Worker }
1230*6777b538SAndroid Build Coastguard Worker
ProcessDoneHeadersQueue(scoped_refptr<ActiveEntry> entry)1231*6777b538SAndroid Build Coastguard Worker void HttpCache::ProcessDoneHeadersQueue(scoped_refptr<ActiveEntry> entry) {
1232*6777b538SAndroid Build Coastguard Worker ParallelWritingPattern writers_pattern;
1233*6777b538SAndroid Build Coastguard Worker DCHECK(!entry->HasWriters() ||
1234*6777b538SAndroid Build Coastguard Worker entry->writers()->CanAddWriters(&writers_pattern));
1235*6777b538SAndroid Build Coastguard Worker DCHECK(!entry->done_headers_queue().empty());
1236*6777b538SAndroid Build Coastguard Worker
1237*6777b538SAndroid Build Coastguard Worker Transaction* transaction = entry->done_headers_queue().front();
1238*6777b538SAndroid Build Coastguard Worker
1239*6777b538SAndroid Build Coastguard Worker ParallelWritingPattern parallel_writing_pattern =
1240*6777b538SAndroid Build Coastguard Worker CanTransactionJoinExistingWriters(transaction);
1241*6777b538SAndroid Build Coastguard Worker if (entry->IsWritingInProgress()) {
1242*6777b538SAndroid Build Coastguard Worker if (parallel_writing_pattern != PARALLEL_WRITING_JOIN) {
1243*6777b538SAndroid Build Coastguard Worker // TODO(shivanisha): Returning from here instead of checking the next
1244*6777b538SAndroid Build Coastguard Worker // transaction in the queue because the FIFO order is maintained
1245*6777b538SAndroid Build Coastguard Worker // throughout, until it becomes a reader or writer. May be at this point
1246*6777b538SAndroid Build Coastguard Worker // the ordering is not important but that would be optimizing a rare
1247*6777b538SAndroid Build Coastguard Worker // scenario where write mode transactions are insterspersed with read-only
1248*6777b538SAndroid Build Coastguard Worker // transactions.
1249*6777b538SAndroid Build Coastguard Worker return;
1250*6777b538SAndroid Build Coastguard Worker }
1251*6777b538SAndroid Build Coastguard Worker entry->AddTransactionToWriters(transaction, parallel_writing_pattern);
1252*6777b538SAndroid Build Coastguard Worker } else { // no writing in progress
1253*6777b538SAndroid Build Coastguard Worker if (transaction->mode() & Transaction::WRITE) {
1254*6777b538SAndroid Build Coastguard Worker if (transaction->partial()) {
1255*6777b538SAndroid Build Coastguard Worker if (entry->readers().empty()) {
1256*6777b538SAndroid Build Coastguard Worker entry->AddTransactionToWriters(transaction, parallel_writing_pattern);
1257*6777b538SAndroid Build Coastguard Worker } else {
1258*6777b538SAndroid Build Coastguard Worker return;
1259*6777b538SAndroid Build Coastguard Worker }
1260*6777b538SAndroid Build Coastguard Worker } else {
1261*6777b538SAndroid Build Coastguard Worker // Add the transaction to readers since the response body should have
1262*6777b538SAndroid Build Coastguard Worker // already been written. (If it was the first writer about to start
1263*6777b538SAndroid Build Coastguard Worker // writing to the cache, it would have been added to writers in
1264*6777b538SAndroid Build Coastguard Worker // DoneWithResponseHeaders, thus no writers here signify the response
1265*6777b538SAndroid Build Coastguard Worker // was completely written).
1266*6777b538SAndroid Build Coastguard Worker transaction->WriteModeTransactionAboutToBecomeReader();
1267*6777b538SAndroid Build Coastguard Worker auto return_val = entry->readers().insert(transaction);
1268*6777b538SAndroid Build Coastguard Worker DCHECK(return_val.second);
1269*6777b538SAndroid Build Coastguard Worker }
1270*6777b538SAndroid Build Coastguard Worker } else { // mode READ
1271*6777b538SAndroid Build Coastguard Worker auto return_val = entry->readers().insert(transaction);
1272*6777b538SAndroid Build Coastguard Worker DCHECK(return_val.second);
1273*6777b538SAndroid Build Coastguard Worker }
1274*6777b538SAndroid Build Coastguard Worker }
1275*6777b538SAndroid Build Coastguard Worker
1276*6777b538SAndroid Build Coastguard Worker // Post another task to give a chance to more transactions to either join
1277*6777b538SAndroid Build Coastguard Worker // readers or another transaction to start parallel validation.
1278*6777b538SAndroid Build Coastguard Worker ProcessQueuedTransactions(entry);
1279*6777b538SAndroid Build Coastguard Worker
1280*6777b538SAndroid Build Coastguard Worker entry->done_headers_queue().erase(entry->done_headers_queue().begin());
1281*6777b538SAndroid Build Coastguard Worker transaction->cache_io_callback().Run(OK);
1282*6777b538SAndroid Build Coastguard Worker }
1283*6777b538SAndroid Build Coastguard Worker
GetLoadStateForPendingTransaction(const Transaction * transaction)1284*6777b538SAndroid Build Coastguard Worker LoadState HttpCache::GetLoadStateForPendingTransaction(
1285*6777b538SAndroid Build Coastguard Worker const Transaction* transaction) {
1286*6777b538SAndroid Build Coastguard Worker auto i = active_entries_.find(transaction->key());
1287*6777b538SAndroid Build Coastguard Worker if (i == active_entries_.end()) {
1288*6777b538SAndroid Build Coastguard Worker // If this is really a pending transaction, and it is not part of
1289*6777b538SAndroid Build Coastguard Worker // active_entries_, we should be creating the backend or the entry.
1290*6777b538SAndroid Build Coastguard Worker return LOAD_STATE_WAITING_FOR_CACHE;
1291*6777b538SAndroid Build Coastguard Worker }
1292*6777b538SAndroid Build Coastguard Worker
1293*6777b538SAndroid Build Coastguard Worker Writers* writers = i->second->writers();
1294*6777b538SAndroid Build Coastguard Worker return !writers ? LOAD_STATE_WAITING_FOR_CACHE : writers->GetLoadState();
1295*6777b538SAndroid Build Coastguard Worker }
1296*6777b538SAndroid Build Coastguard Worker
RemovePendingTransaction(Transaction * transaction)1297*6777b538SAndroid Build Coastguard Worker void HttpCache::RemovePendingTransaction(Transaction* transaction) {
1298*6777b538SAndroid Build Coastguard Worker auto i = active_entries_.find(transaction->key());
1299*6777b538SAndroid Build Coastguard Worker bool found = false;
1300*6777b538SAndroid Build Coastguard Worker if (i != active_entries_.end()) {
1301*6777b538SAndroid Build Coastguard Worker found = i->second->RemovePendingTransaction(transaction);
1302*6777b538SAndroid Build Coastguard Worker }
1303*6777b538SAndroid Build Coastguard Worker
1304*6777b538SAndroid Build Coastguard Worker if (found) {
1305*6777b538SAndroid Build Coastguard Worker return;
1306*6777b538SAndroid Build Coastguard Worker }
1307*6777b538SAndroid Build Coastguard Worker
1308*6777b538SAndroid Build Coastguard Worker if (building_backend_) {
1309*6777b538SAndroid Build Coastguard Worker auto j = pending_ops_.find(std::string());
1310*6777b538SAndroid Build Coastguard Worker if (j != pending_ops_.end()) {
1311*6777b538SAndroid Build Coastguard Worker found = RemovePendingTransactionFromPendingOp(j->second, transaction);
1312*6777b538SAndroid Build Coastguard Worker }
1313*6777b538SAndroid Build Coastguard Worker
1314*6777b538SAndroid Build Coastguard Worker if (found) {
1315*6777b538SAndroid Build Coastguard Worker return;
1316*6777b538SAndroid Build Coastguard Worker }
1317*6777b538SAndroid Build Coastguard Worker }
1318*6777b538SAndroid Build Coastguard Worker
1319*6777b538SAndroid Build Coastguard Worker auto j = pending_ops_.find(transaction->key());
1320*6777b538SAndroid Build Coastguard Worker if (j != pending_ops_.end()) {
1321*6777b538SAndroid Build Coastguard Worker found = RemovePendingTransactionFromPendingOp(j->second, transaction);
1322*6777b538SAndroid Build Coastguard Worker }
1323*6777b538SAndroid Build Coastguard Worker
1324*6777b538SAndroid Build Coastguard Worker if (found) {
1325*6777b538SAndroid Build Coastguard Worker return;
1326*6777b538SAndroid Build Coastguard Worker }
1327*6777b538SAndroid Build Coastguard Worker
1328*6777b538SAndroid Build Coastguard Worker for (auto k = doomed_entries_.begin(); k != doomed_entries_.end() && !found;
1329*6777b538SAndroid Build Coastguard Worker ++k) {
1330*6777b538SAndroid Build Coastguard Worker // TODO(ricea): Add unit test for this line.
1331*6777b538SAndroid Build Coastguard Worker found = k->get().RemovePendingTransaction(transaction);
1332*6777b538SAndroid Build Coastguard Worker }
1333*6777b538SAndroid Build Coastguard Worker
1334*6777b538SAndroid Build Coastguard Worker DCHECK(found) << "Pending transaction not found";
1335*6777b538SAndroid Build Coastguard Worker }
1336*6777b538SAndroid Build Coastguard Worker
RemovePendingTransactionFromPendingOp(PendingOp * pending_op,Transaction * transaction)1337*6777b538SAndroid Build Coastguard Worker bool HttpCache::RemovePendingTransactionFromPendingOp(
1338*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op,
1339*6777b538SAndroid Build Coastguard Worker Transaction* transaction) {
1340*6777b538SAndroid Build Coastguard Worker if (pending_op->writer->Matches(transaction)) {
1341*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearTransaction();
1342*6777b538SAndroid Build Coastguard Worker pending_op->writer->ClearEntry();
1343*6777b538SAndroid Build Coastguard Worker return true;
1344*6777b538SAndroid Build Coastguard Worker }
1345*6777b538SAndroid Build Coastguard Worker WorkItemList& pending_queue = pending_op->pending_queue;
1346*6777b538SAndroid Build Coastguard Worker
1347*6777b538SAndroid Build Coastguard Worker for (auto it = pending_queue.begin(); it != pending_queue.end(); ++it) {
1348*6777b538SAndroid Build Coastguard Worker if ((*it)->Matches(transaction)) {
1349*6777b538SAndroid Build Coastguard Worker pending_queue.erase(it);
1350*6777b538SAndroid Build Coastguard Worker return true;
1351*6777b538SAndroid Build Coastguard Worker }
1352*6777b538SAndroid Build Coastguard Worker }
1353*6777b538SAndroid Build Coastguard Worker return false;
1354*6777b538SAndroid Build Coastguard Worker }
1355*6777b538SAndroid Build Coastguard Worker
OnProcessQueuedTransactions(scoped_refptr<ActiveEntry> entry)1356*6777b538SAndroid Build Coastguard Worker void HttpCache::OnProcessQueuedTransactions(scoped_refptr<ActiveEntry> entry) {
1357*6777b538SAndroid Build Coastguard Worker entry->set_will_process_queued_transactions(false);
1358*6777b538SAndroid Build Coastguard Worker
1359*6777b538SAndroid Build Coastguard Worker // Note that this function should only invoke one transaction's IO callback
1360*6777b538SAndroid Build Coastguard Worker // since its possible for IO callbacks' consumers to destroy the cache/entry.
1361*6777b538SAndroid Build Coastguard Worker
1362*6777b538SAndroid Build Coastguard Worker if (entry->done_headers_queue().empty() &&
1363*6777b538SAndroid Build Coastguard Worker entry->add_to_entry_queue().empty()) {
1364*6777b538SAndroid Build Coastguard Worker return;
1365*6777b538SAndroid Build Coastguard Worker }
1366*6777b538SAndroid Build Coastguard Worker
1367*6777b538SAndroid Build Coastguard Worker // To maintain FIFO order of transactions, done_headers_queue should be
1368*6777b538SAndroid Build Coastguard Worker // checked for processing before add_to_entry_queue.
1369*6777b538SAndroid Build Coastguard Worker
1370*6777b538SAndroid Build Coastguard Worker // If another transaction is writing the response, let validated transactions
1371*6777b538SAndroid Build Coastguard Worker // wait till the response is complete. If the response is not yet started, the
1372*6777b538SAndroid Build Coastguard Worker // done_headers_queue transaction should start writing it.
1373*6777b538SAndroid Build Coastguard Worker if (!entry->done_headers_queue().empty()) {
1374*6777b538SAndroid Build Coastguard Worker ParallelWritingPattern unused_reason;
1375*6777b538SAndroid Build Coastguard Worker if (!entry->writers() || entry->writers()->CanAddWriters(&unused_reason)) {
1376*6777b538SAndroid Build Coastguard Worker ProcessDoneHeadersQueue(entry);
1377*6777b538SAndroid Build Coastguard Worker return;
1378*6777b538SAndroid Build Coastguard Worker }
1379*6777b538SAndroid Build Coastguard Worker }
1380*6777b538SAndroid Build Coastguard Worker
1381*6777b538SAndroid Build Coastguard Worker if (!entry->add_to_entry_queue().empty()) {
1382*6777b538SAndroid Build Coastguard Worker ProcessAddToEntryQueue(std::move(entry));
1383*6777b538SAndroid Build Coastguard Worker }
1384*6777b538SAndroid Build Coastguard Worker }
1385*6777b538SAndroid Build Coastguard Worker
OnIOComplete(int result,PendingOp * pending_op)1386*6777b538SAndroid Build Coastguard Worker void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1387*6777b538SAndroid Build Coastguard Worker WorkItemOperation op = pending_op->writer->operation();
1388*6777b538SAndroid Build Coastguard Worker
1389*6777b538SAndroid Build Coastguard Worker // Completing the creation of the backend is simpler than the other cases.
1390*6777b538SAndroid Build Coastguard Worker if (op == WI_CREATE_BACKEND) {
1391*6777b538SAndroid Build Coastguard Worker return OnBackendCreated(result, pending_op);
1392*6777b538SAndroid Build Coastguard Worker }
1393*6777b538SAndroid Build Coastguard Worker
1394*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
1395*6777b538SAndroid Build Coastguard Worker bool try_restart_requests = false;
1396*6777b538SAndroid Build Coastguard Worker
1397*6777b538SAndroid Build Coastguard Worker scoped_refptr<ActiveEntry> entry;
1398*6777b538SAndroid Build Coastguard Worker std::string key;
1399*6777b538SAndroid Build Coastguard Worker if (result == OK) {
1400*6777b538SAndroid Build Coastguard Worker if (op == WI_DOOM_ENTRY) {
1401*6777b538SAndroid Build Coastguard Worker // Anything after a Doom has to be restarted.
1402*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1403*6777b538SAndroid Build Coastguard Worker } else if (item->IsValid()) {
1404*6777b538SAndroid Build Coastguard Worker DCHECK(pending_op->entry);
1405*6777b538SAndroid Build Coastguard Worker key = pending_op->entry->GetKey();
1406*6777b538SAndroid Build Coastguard Worker entry = ActivateEntry(pending_op->entry, pending_op->entry_opened);
1407*6777b538SAndroid Build Coastguard Worker } else {
1408*6777b538SAndroid Build Coastguard Worker // The writer transaction is gone.
1409*6777b538SAndroid Build Coastguard Worker if (!pending_op->entry_opened) {
1410*6777b538SAndroid Build Coastguard Worker pending_op->entry->Doom();
1411*6777b538SAndroid Build Coastguard Worker }
1412*6777b538SAndroid Build Coastguard Worker
1413*6777b538SAndroid Build Coastguard Worker pending_op->entry->Close();
1414*6777b538SAndroid Build Coastguard Worker pending_op->entry = nullptr;
1415*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1416*6777b538SAndroid Build Coastguard Worker }
1417*6777b538SAndroid Build Coastguard Worker }
1418*6777b538SAndroid Build Coastguard Worker
1419*6777b538SAndroid Build Coastguard Worker // We are about to notify a bunch of transactions, and they may decide to
1420*6777b538SAndroid Build Coastguard Worker // re-issue a request (or send a different one). If we don't delete
1421*6777b538SAndroid Build Coastguard Worker // pending_op, the new request will be appended to the end of the list, and
1422*6777b538SAndroid Build Coastguard Worker // we'll see it again from this point before it has a chance to complete (and
1423*6777b538SAndroid Build Coastguard Worker // we'll be messing out the request order). The down side is that if for some
1424*6777b538SAndroid Build Coastguard Worker // reason notifying request A ends up cancelling request B (for the same key),
1425*6777b538SAndroid Build Coastguard Worker // we won't find request B anywhere (because it would be in a local variable
1426*6777b538SAndroid Build Coastguard Worker // here) and that's bad. If there is a chance for that to happen, we'll have
1427*6777b538SAndroid Build Coastguard Worker // to move the callback used to be a CancelableOnceCallback. By the way, for
1428*6777b538SAndroid Build Coastguard Worker // this to happen the action (to cancel B) has to be synchronous to the
1429*6777b538SAndroid Build Coastguard Worker // notification for request A.
1430*6777b538SAndroid Build Coastguard Worker WorkItemList pending_items = std::move(pending_op->pending_queue);
1431*6777b538SAndroid Build Coastguard Worker DeletePendingOp(pending_op);
1432*6777b538SAndroid Build Coastguard Worker
1433*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(result, entry);
1434*6777b538SAndroid Build Coastguard Worker
1435*6777b538SAndroid Build Coastguard Worker while (!pending_items.empty()) {
1436*6777b538SAndroid Build Coastguard Worker item = std::move(pending_items.front());
1437*6777b538SAndroid Build Coastguard Worker pending_items.pop_front();
1438*6777b538SAndroid Build Coastguard Worker
1439*6777b538SAndroid Build Coastguard Worker if (item->operation() == WI_DOOM_ENTRY) {
1440*6777b538SAndroid Build Coastguard Worker // A queued doom request is always a race.
1441*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1442*6777b538SAndroid Build Coastguard Worker } else if (result == OK) {
1443*6777b538SAndroid Build Coastguard Worker entry = GetActiveEntry(key);
1444*6777b538SAndroid Build Coastguard Worker if (!entry) {
1445*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1446*6777b538SAndroid Build Coastguard Worker }
1447*6777b538SAndroid Build Coastguard Worker }
1448*6777b538SAndroid Build Coastguard Worker
1449*6777b538SAndroid Build Coastguard Worker if (try_restart_requests) {
1450*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(ERR_CACHE_RACE, nullptr);
1451*6777b538SAndroid Build Coastguard Worker continue;
1452*6777b538SAndroid Build Coastguard Worker }
1453*6777b538SAndroid Build Coastguard Worker // At this point item->operation() is anything except Doom.
1454*6777b538SAndroid Build Coastguard Worker if (item->operation() == WI_CREATE_ENTRY) {
1455*6777b538SAndroid Build Coastguard Worker if (result == OK) {
1456*6777b538SAndroid Build Coastguard Worker // Successful OpenOrCreate, Open, or Create followed by a Create.
1457*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(ERR_CACHE_CREATE_FAILURE, nullptr);
1458*6777b538SAndroid Build Coastguard Worker } else {
1459*6777b538SAndroid Build Coastguard Worker if (op != WI_CREATE_ENTRY && op != WI_OPEN_OR_CREATE_ENTRY) {
1460*6777b538SAndroid Build Coastguard Worker // Failed Open or Doom followed by a Create.
1461*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(ERR_CACHE_RACE, nullptr);
1462*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1463*6777b538SAndroid Build Coastguard Worker } else {
1464*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(result, entry);
1465*6777b538SAndroid Build Coastguard Worker }
1466*6777b538SAndroid Build Coastguard Worker }
1467*6777b538SAndroid Build Coastguard Worker }
1468*6777b538SAndroid Build Coastguard Worker // item->operation() is OpenOrCreate or Open
1469*6777b538SAndroid Build Coastguard Worker else if (item->operation() == WI_OPEN_OR_CREATE_ENTRY) {
1470*6777b538SAndroid Build Coastguard Worker if ((op == WI_OPEN_ENTRY || op == WI_CREATE_ENTRY) && result != OK) {
1471*6777b538SAndroid Build Coastguard Worker // Failed Open or Create followed by an OpenOrCreate.
1472*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(ERR_CACHE_RACE, nullptr);
1473*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1474*6777b538SAndroid Build Coastguard Worker } else {
1475*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(result, entry);
1476*6777b538SAndroid Build Coastguard Worker }
1477*6777b538SAndroid Build Coastguard Worker }
1478*6777b538SAndroid Build Coastguard Worker // item->operation() is Open.
1479*6777b538SAndroid Build Coastguard Worker else {
1480*6777b538SAndroid Build Coastguard Worker if (op == WI_CREATE_ENTRY && result != OK) {
1481*6777b538SAndroid Build Coastguard Worker // Failed Create followed by an Open.
1482*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(ERR_CACHE_RACE, nullptr);
1483*6777b538SAndroid Build Coastguard Worker try_restart_requests = true;
1484*6777b538SAndroid Build Coastguard Worker } else {
1485*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(result, entry);
1486*6777b538SAndroid Build Coastguard Worker }
1487*6777b538SAndroid Build Coastguard Worker }
1488*6777b538SAndroid Build Coastguard Worker }
1489*6777b538SAndroid Build Coastguard Worker }
1490*6777b538SAndroid Build Coastguard Worker
1491*6777b538SAndroid Build Coastguard Worker // static
OnPendingOpComplete(base::WeakPtr<HttpCache> cache,PendingOp * pending_op,int rv)1492*6777b538SAndroid Build Coastguard Worker void HttpCache::OnPendingOpComplete(base::WeakPtr<HttpCache> cache,
1493*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op,
1494*6777b538SAndroid Build Coastguard Worker int rv) {
1495*6777b538SAndroid Build Coastguard Worker if (cache.get()) {
1496*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = false;
1497*6777b538SAndroid Build Coastguard Worker cache->OnIOComplete(rv, pending_op);
1498*6777b538SAndroid Build Coastguard Worker } else {
1499*6777b538SAndroid Build Coastguard Worker // The callback was cancelled so we should delete the pending_op that
1500*6777b538SAndroid Build Coastguard Worker // was used with this callback.
1501*6777b538SAndroid Build Coastguard Worker delete pending_op;
1502*6777b538SAndroid Build Coastguard Worker }
1503*6777b538SAndroid Build Coastguard Worker }
1504*6777b538SAndroid Build Coastguard Worker
1505*6777b538SAndroid Build Coastguard Worker // static
OnPendingCreationOpComplete(base::WeakPtr<HttpCache> cache,PendingOp * pending_op,disk_cache::EntryResult result)1506*6777b538SAndroid Build Coastguard Worker void HttpCache::OnPendingCreationOpComplete(base::WeakPtr<HttpCache> cache,
1507*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op,
1508*6777b538SAndroid Build Coastguard Worker disk_cache::EntryResult result) {
1509*6777b538SAndroid Build Coastguard Worker if (!cache.get()) {
1510*6777b538SAndroid Build Coastguard Worker // The callback was cancelled so we should delete the pending_op that
1511*6777b538SAndroid Build Coastguard Worker // was used with this callback. If |result| contains a fresh entry
1512*6777b538SAndroid Build Coastguard Worker // it will close it automatically, since we don't release it here.
1513*6777b538SAndroid Build Coastguard Worker delete pending_op;
1514*6777b538SAndroid Build Coastguard Worker return;
1515*6777b538SAndroid Build Coastguard Worker }
1516*6777b538SAndroid Build Coastguard Worker
1517*6777b538SAndroid Build Coastguard Worker int rv = result.net_error();
1518*6777b538SAndroid Build Coastguard Worker pending_op->entry_opened = result.opened();
1519*6777b538SAndroid Build Coastguard Worker pending_op->entry = result.ReleaseEntry();
1520*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = false;
1521*6777b538SAndroid Build Coastguard Worker cache->OnIOComplete(rv, pending_op);
1522*6777b538SAndroid Build Coastguard Worker }
1523*6777b538SAndroid Build Coastguard Worker
1524*6777b538SAndroid Build Coastguard Worker // static
OnPendingBackendCreationOpComplete(base::WeakPtr<HttpCache> cache,PendingOp * pending_op,disk_cache::BackendResult result)1525*6777b538SAndroid Build Coastguard Worker void HttpCache::OnPendingBackendCreationOpComplete(
1526*6777b538SAndroid Build Coastguard Worker base::WeakPtr<HttpCache> cache,
1527*6777b538SAndroid Build Coastguard Worker PendingOp* pending_op,
1528*6777b538SAndroid Build Coastguard Worker disk_cache::BackendResult result) {
1529*6777b538SAndroid Build Coastguard Worker if (!cache.get()) {
1530*6777b538SAndroid Build Coastguard Worker // The callback was cancelled so we should delete the pending_op that
1531*6777b538SAndroid Build Coastguard Worker // was used with this callback. If `result` contains a cache backend,
1532*6777b538SAndroid Build Coastguard Worker // it will be destroyed with it.
1533*6777b538SAndroid Build Coastguard Worker delete pending_op;
1534*6777b538SAndroid Build Coastguard Worker return;
1535*6777b538SAndroid Build Coastguard Worker }
1536*6777b538SAndroid Build Coastguard Worker
1537*6777b538SAndroid Build Coastguard Worker int rv = result.net_error;
1538*6777b538SAndroid Build Coastguard Worker pending_op->backend = std::move(result.backend);
1539*6777b538SAndroid Build Coastguard Worker pending_op->callback_will_delete = false;
1540*6777b538SAndroid Build Coastguard Worker cache->OnIOComplete(rv, pending_op);
1541*6777b538SAndroid Build Coastguard Worker }
1542*6777b538SAndroid Build Coastguard Worker
OnBackendCreated(int result,PendingOp * pending_op)1543*6777b538SAndroid Build Coastguard Worker void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) {
1544*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WorkItem> item = std::move(pending_op->writer);
1545*6777b538SAndroid Build Coastguard Worker WorkItemOperation op = item->operation();
1546*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(WI_CREATE_BACKEND, op);
1547*6777b538SAndroid Build Coastguard Worker
1548*6777b538SAndroid Build Coastguard Worker if (backend_factory_.get()) {
1549*6777b538SAndroid Build Coastguard Worker // We may end up calling OnBackendCreated multiple times if we have pending
1550*6777b538SAndroid Build Coastguard Worker // work items. The first call saves the backend and releases the factory,
1551*6777b538SAndroid Build Coastguard Worker // and the last call clears building_backend_.
1552*6777b538SAndroid Build Coastguard Worker backend_factory_.reset(); // Reclaim memory.
1553*6777b538SAndroid Build Coastguard Worker if (result == OK) {
1554*6777b538SAndroid Build Coastguard Worker disk_cache_ = std::move(pending_op->backend);
1555*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_MEMORY_KB("HttpCache.MaxFileSizeOnInit",
1556*6777b538SAndroid Build Coastguard Worker disk_cache_->MaxFileSize() / 1024);
1557*6777b538SAndroid Build Coastguard Worker }
1558*6777b538SAndroid Build Coastguard Worker }
1559*6777b538SAndroid Build Coastguard Worker
1560*6777b538SAndroid Build Coastguard Worker if (!pending_op->pending_queue.empty()) {
1561*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WorkItem> pending_item =
1562*6777b538SAndroid Build Coastguard Worker std::move(pending_op->pending_queue.front());
1563*6777b538SAndroid Build Coastguard Worker pending_op->pending_queue.pop_front();
1564*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation());
1565*6777b538SAndroid Build Coastguard Worker
1566*6777b538SAndroid Build Coastguard Worker // We want to process a single callback at a time, because the cache may
1567*6777b538SAndroid Build Coastguard Worker // go away from the callback.
1568*6777b538SAndroid Build Coastguard Worker pending_op->writer = std::move(pending_item);
1569*6777b538SAndroid Build Coastguard Worker
1570*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1571*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(&HttpCache::OnBackendCreated, GetWeakPtr(),
1572*6777b538SAndroid Build Coastguard Worker result, pending_op));
1573*6777b538SAndroid Build Coastguard Worker } else {
1574*6777b538SAndroid Build Coastguard Worker building_backend_ = false;
1575*6777b538SAndroid Build Coastguard Worker DeletePendingOp(pending_op);
1576*6777b538SAndroid Build Coastguard Worker }
1577*6777b538SAndroid Build Coastguard Worker
1578*6777b538SAndroid Build Coastguard Worker // The cache may be gone when we return from the callback.
1579*6777b538SAndroid Build Coastguard Worker if (!item->DoCallback(result)) {
1580*6777b538SAndroid Build Coastguard Worker item->NotifyTransaction(result, nullptr);
1581*6777b538SAndroid Build Coastguard Worker }
1582*6777b538SAndroid Build Coastguard Worker }
1583*6777b538SAndroid Build Coastguard Worker
1584*6777b538SAndroid Build Coastguard Worker } // namespace net
1585