1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_cache.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/files/file_util.h"
14 #include "base/format_macros.h"
15 #include "base/location.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/metrics/field_trial.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/pickle.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/stl_util.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/thread_task_runner_handle.h"
26 #include "base/threading/worker_pool.h"
27 #include "base/time/default_clock.h"
28 #include "base/time/time.h"
29 #include "net/base/cache_type.h"
30 #include "net/base/io_buffer.h"
31 #include "net/base/load_flags.h"
32 #include "net/base/net_errors.h"
33 #include "net/base/upload_data_stream.h"
34 #include "net/disk_cache/disk_cache.h"
35 #include "net/http/disk_based_cert_cache.h"
36 #include "net/http/disk_cache_based_quic_server_info.h"
37 #include "net/http/http_cache_transaction.h"
38 #include "net/http/http_network_layer.h"
39 #include "net/http/http_network_session.h"
40 #include "net/http/http_request_info.h"
41 #include "net/http/http_response_headers.h"
42 #include "net/http/http_response_info.h"
43 #include "net/http/http_util.h"
44 #include "net/quic/crypto/quic_server_info.h"
53 return base::FieldTrialList::FindFullName("CertCacheTrial") ==
61 HttpCache::DefaultBackend::DefaultBackend(
63 BackendType backend_type
,
64 const base::FilePath
& path
,
66 const scoped_refptr
<base::SingleThreadTaskRunner
>& thread
)
68 backend_type_(backend_type
),
70 max_bytes_(max_bytes
),
74 HttpCache::DefaultBackend::~DefaultBackend() {}
77 HttpCache::BackendFactory
* HttpCache::DefaultBackend::InMemory(int max_bytes
) {
78 return new DefaultBackend(MEMORY_CACHE
, CACHE_BACKEND_DEFAULT
,
79 base::FilePath(), max_bytes
, NULL
);
82 int HttpCache::DefaultBackend::CreateBackend(
83 NetLog
* net_log
, scoped_ptr
<disk_cache::Backend
>* backend
,
84 const CompletionCallback
& callback
) {
85 DCHECK_GE(max_bytes_
, 0);
86 return disk_cache::CreateCacheBackend(type_
,
97 //-----------------------------------------------------------------------------
99 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry
* entry
)
102 will_process_pending_queue(false),
106 HttpCache::ActiveEntry::~ActiveEntry() {
113 //-----------------------------------------------------------------------------
115 // This structure keeps track of work items that are attempting to create or
116 // open cache entries or the backend itself.
117 struct HttpCache::PendingOp
{
118 PendingOp() : disk_entry(NULL
), writer(NULL
) {}
121 disk_cache::Entry
* disk_entry
;
122 scoped_ptr
<disk_cache::Backend
> backend
;
124 CompletionCallback callback
; // BackendCallback.
125 WorkItemList pending_queue
;
128 //-----------------------------------------------------------------------------
130 // The type of operation represented by a work item.
131 enum WorkItemOperation
{
138 // A work item encapsulates a single request to the backend with all the
139 // information needed to complete that request.
140 class HttpCache::WorkItem
{
142 WorkItem(WorkItemOperation operation
, Transaction
* trans
, ActiveEntry
** entry
)
143 : operation_(operation
),
147 WorkItem(WorkItemOperation operation
,
149 const CompletionCallback
& cb
,
150 disk_cache::Backend
** backend
)
151 : operation_(operation
),
158 // Calls back the transaction with the result of the operation.
159 void NotifyTransaction(int result
, ActiveEntry
* entry
) {
160 DCHECK(!entry
|| entry
->disk_entry
);
164 trans_
->io_callback().Run(result
);
167 // Notifies the caller about the operation completion. Returns true if the
168 // callback was invoked.
169 bool DoCallback(int result
, disk_cache::Backend
* backend
) {
172 if (!callback_
.is_null()) {
173 callback_
.Run(result
);
179 WorkItemOperation
operation() { return operation_
; }
180 void ClearTransaction() { trans_
= NULL
; }
181 void ClearEntry() { entry_
= NULL
; }
182 void ClearCallback() { callback_
.Reset(); }
183 bool Matches(Transaction
* trans
) const { return trans
== trans_
; }
184 bool IsValid() const { return trans_
|| entry_
|| !callback_
.is_null(); }
187 WorkItemOperation operation_
;
189 ActiveEntry
** entry_
;
190 CompletionCallback callback_
; // User callback.
191 disk_cache::Backend
** backend_
;
194 //-----------------------------------------------------------------------------
196 // This class encapsulates a transaction whose only purpose is to write metadata
198 class HttpCache::MetadataWriter
{
200 explicit MetadataWriter(HttpCache::Transaction
* trans
)
201 : transaction_(trans
),
208 // Implements the bulk of HttpCache::WriteMetadata.
209 void Write(const GURL
& url
,
210 base::Time expected_response_time
,
215 void VerifyResponse(int result
);
217 void OnIOComplete(int result
);
219 scoped_ptr
<HttpCache::Transaction
> transaction_
;
221 scoped_refptr
<IOBuffer
> buf_
;
223 base::Time expected_response_time_
;
224 HttpRequestInfo request_info_
;
225 DISALLOW_COPY_AND_ASSIGN(MetadataWriter
);
228 void HttpCache::MetadataWriter::Write(const GURL
& url
,
229 base::Time expected_response_time
,
232 DCHECK_GT(buf_len
, 0);
235 request_info_
.url
= url
;
236 request_info_
.method
= "GET";
237 request_info_
.load_flags
= LOAD_ONLY_FROM_CACHE
;
239 expected_response_time_
= expected_response_time
;
244 int rv
= transaction_
->Start(
246 base::Bind(&MetadataWriter::OnIOComplete
, base::Unretained(this)),
248 if (rv
!= ERR_IO_PENDING
)
252 void HttpCache::MetadataWriter::VerifyResponse(int result
) {
255 return SelfDestroy();
257 const HttpResponseInfo
* response_info
= transaction_
->GetResponseInfo();
258 DCHECK(response_info
->was_cached
);
259 if (response_info
->response_time
!= expected_response_time_
)
260 return SelfDestroy();
262 result
= transaction_
->WriteMetadata(
265 base::Bind(&MetadataWriter::OnIOComplete
, base::Unretained(this)));
266 if (result
!= ERR_IO_PENDING
)
270 void HttpCache::MetadataWriter::SelfDestroy() {
274 void HttpCache::MetadataWriter::OnIOComplete(int result
) {
276 return VerifyResponse(result
);
280 //-----------------------------------------------------------------------------
282 class HttpCache::QuicServerInfoFactoryAdaptor
: public QuicServerInfoFactory
{
284 explicit QuicServerInfoFactoryAdaptor(HttpCache
* http_cache
)
285 : http_cache_(http_cache
) {
288 QuicServerInfo
* GetForServer(const QuicServerId
& server_id
) override
{
289 return new DiskCacheBasedQuicServerInfo(server_id
, http_cache_
);
293 HttpCache
* const http_cache_
;
296 //-----------------------------------------------------------------------------
297 HttpCache::HttpCache(const HttpNetworkSession::Params
& params
,
298 BackendFactory
* backend_factory
)
299 : net_log_(params
.net_log
),
300 backend_factory_(backend_factory
),
301 building_backend_(false),
302 bypass_lock_for_test_(false),
303 fail_conditionalization_for_test_(false),
305 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params
))),
306 clock_(new base::DefaultClock()),
307 weak_factory_(this) {
308 SetupQuicServerInfoFactory(network_layer_
->GetSession());
312 // This call doesn't change the shared |session|'s QuicServerInfoFactory because
313 // |session| is shared.
314 HttpCache::HttpCache(HttpNetworkSession
* session
,
315 BackendFactory
* backend_factory
)
316 : net_log_(session
->net_log()),
317 backend_factory_(backend_factory
),
318 building_backend_(false),
319 bypass_lock_for_test_(false),
320 fail_conditionalization_for_test_(false),
322 network_layer_(new HttpNetworkLayer(session
)),
323 clock_(new base::DefaultClock()),
324 weak_factory_(this) {
327 HttpCache::HttpCache(HttpTransactionFactory
* network_layer
,
329 BackendFactory
* backend_factory
)
331 backend_factory_(backend_factory
),
332 building_backend_(false),
333 bypass_lock_for_test_(false),
334 fail_conditionalization_for_test_(false),
336 network_layer_(network_layer
),
337 clock_(new base::DefaultClock()),
338 weak_factory_(this) {
339 SetupQuicServerInfoFactory(network_layer_
->GetSession());
342 HttpCache::~HttpCache() {
343 // Transactions should see an invalid cache after this point; otherwise they
344 // could see an inconsistent object (half destroyed).
345 weak_factory_
.InvalidateWeakPtrs();
347 // If we have any active entries remaining, then we need to deactivate them.
348 // We may have some pending calls to OnProcessPendingQueue, but since those
349 // won't run (due to our destruction), we can simply ignore the corresponding
350 // will_process_pending_queue flag.
351 while (!active_entries_
.empty()) {
352 ActiveEntry
* entry
= active_entries_
.begin()->second
;
353 entry
->will_process_pending_queue
= false;
354 entry
->pending_queue
.clear();
355 entry
->readers
.clear();
356 entry
->writer
= NULL
;
357 DeactivateEntry(entry
);
360 STLDeleteElements(&doomed_entries_
);
362 // Before deleting pending_ops_, we have to make sure that the disk cache is
363 // done with said operations, or it will attempt to use deleted data.
367 PendingOpsMap::iterator pending_it
= pending_ops_
.begin();
368 for (; pending_it
!= pending_ops_
.end(); ++pending_it
) {
369 // We are not notifying the transactions about the cache going away, even
370 // though they are waiting for a callback that will never fire.
371 PendingOp
* pending_op
= pending_it
->second
;
372 delete pending_op
->writer
;
373 bool delete_pending_op
= true;
374 if (building_backend_
) {
375 // If we don't have a backend, when its construction finishes it will
376 // deliver the callbacks.
377 if (!pending_op
->callback
.is_null()) {
378 // If not null, the callback will delete the pending operation later.
379 delete_pending_op
= false;
382 pending_op
->callback
.Reset();
385 STLDeleteElements(&pending_op
->pending_queue
);
386 if (delete_pending_op
)
391 int HttpCache::GetBackend(disk_cache::Backend
** backend
,
392 const CompletionCallback
& callback
) {
393 DCHECK(!callback
.is_null());
395 if (disk_cache_
.get()) {
396 *backend
= disk_cache_
.get();
400 return CreateBackend(backend
, callback
);
403 disk_cache::Backend
* HttpCache::GetCurrentBackend() const {
404 return disk_cache_
.get();
408 bool HttpCache::ParseResponseInfo(const char* data
, int len
,
409 HttpResponseInfo
* response_info
,
410 bool* response_truncated
) {
411 base::Pickle
pickle(data
, len
);
412 return response_info
->InitFromPickle(pickle
, response_truncated
);
415 void HttpCache::WriteMetadata(const GURL
& url
,
416 RequestPriority priority
,
417 base::Time expected_response_time
,
423 // Do lazy initialization of disk cache if needed.
424 if (!disk_cache_
.get()) {
425 // We don't care about the result.
426 CreateBackend(NULL
, CompletionCallback());
429 HttpCache::Transaction
* trans
=
430 new HttpCache::Transaction(priority
, this);
431 MetadataWriter
* writer
= new MetadataWriter(trans
);
433 // The writer will self destruct when done.
434 writer
->Write(url
, expected_response_time
, buf
, buf_len
);
437 void HttpCache::CloseAllConnections() {
438 HttpNetworkSession
* session
= GetSession();
440 session
->CloseAllConnections();
443 void HttpCache::CloseIdleConnections() {
444 HttpNetworkSession
* session
= GetSession();
446 session
->CloseIdleConnections();
449 void HttpCache::OnExternalCacheHit(const GURL
& url
,
450 const std::string
& http_method
) {
451 if (!disk_cache_
.get() || mode_
== DISABLE
)
454 HttpRequestInfo request_info
;
455 request_info
.url
= url
;
456 request_info
.method
= http_method
;
457 std::string key
= GenerateCacheKey(&request_info
);
458 disk_cache_
->OnExternalCacheHit(key
);
461 int HttpCache::CreateTransaction(RequestPriority priority
,
462 scoped_ptr
<HttpTransaction
>* trans
) {
463 // Do lazy initialization of disk cache if needed.
464 if (!disk_cache_
.get()) {
465 // We don't care about the result.
466 CreateBackend(NULL
, CompletionCallback());
469 HttpCache::Transaction
* transaction
=
470 new HttpCache::Transaction(priority
, this);
471 if (bypass_lock_for_test_
)
472 transaction
->BypassLockForTest();
473 if (fail_conditionalization_for_test_
)
474 transaction
->FailConditionalizationForTest();
476 trans
->reset(transaction
);
480 HttpCache
* HttpCache::GetCache() {
484 HttpNetworkSession
* HttpCache::GetSession() {
485 return network_layer_
->GetSession();
488 scoped_ptr
<HttpTransactionFactory
>
489 HttpCache::SetHttpNetworkTransactionFactoryForTesting(
490 scoped_ptr
<HttpTransactionFactory
> new_network_layer
) {
491 scoped_ptr
<HttpTransactionFactory
> old_network_layer(network_layer_
.Pass());
492 network_layer_
= new_network_layer
.Pass();
493 return old_network_layer
.Pass();
496 //-----------------------------------------------------------------------------
498 int HttpCache::CreateBackend(disk_cache::Backend
** backend
,
499 const CompletionCallback
& callback
) {
500 if (!backend_factory_
.get())
503 building_backend_
= true;
505 scoped_ptr
<WorkItem
> item(new WorkItem(WI_CREATE_BACKEND
, NULL
, callback
,
508 // This is the only operation that we can do that is not related to any given
509 // entry, so we use an empty key for it.
510 PendingOp
* pending_op
= GetPendingOp(std::string());
511 if (pending_op
->writer
) {
512 if (!callback
.is_null())
513 pending_op
->pending_queue
.push_back(item
.release());
514 return ERR_IO_PENDING
;
517 DCHECK(pending_op
->pending_queue
.empty());
519 pending_op
->writer
= item
.release();
520 pending_op
->callback
= base::Bind(&HttpCache::OnPendingOpComplete
,
521 GetWeakPtr(), pending_op
);
523 int rv
= backend_factory_
->CreateBackend(net_log_
, &pending_op
->backend
,
524 pending_op
->callback
);
525 if (rv
!= ERR_IO_PENDING
) {
526 pending_op
->writer
->ClearCallback();
527 pending_op
->callback
.Run(rv
);
533 int HttpCache::GetBackendForTransaction(Transaction
* trans
) {
534 if (disk_cache_
.get())
537 if (!building_backend_
)
541 new WorkItem(WI_CREATE_BACKEND
, trans
, CompletionCallback(), NULL
);
542 PendingOp
* pending_op
= GetPendingOp(std::string());
543 DCHECK(pending_op
->writer
);
544 pending_op
->pending_queue
.push_back(item
);
545 return ERR_IO_PENDING
;
548 // Generate a key that can be used inside the cache.
549 std::string
HttpCache::GenerateCacheKey(const HttpRequestInfo
* request
) {
550 // Strip out the reference, username, and password sections of the URL.
551 std::string url
= HttpUtil::SpecForRequest(request
->url
);
553 DCHECK_NE(DISABLE
, mode_
);
554 // No valid URL can begin with numerals, so we should not have to worry
555 // about collisions with normal URLs.
556 if (request
->upload_data_stream
&&
557 request
->upload_data_stream
->identifier()) {
559 base::StringPrintf("%" PRId64
"/",
560 request
->upload_data_stream
->identifier()));
565 void HttpCache::DoomActiveEntry(const std::string
& key
) {
566 ActiveEntriesMap::iterator it
= active_entries_
.find(key
);
567 if (it
== active_entries_
.end())
570 // This is not a performance critical operation, this is handling an error
571 // condition so it is OK to look up the entry again.
572 int rv
= DoomEntry(key
, NULL
);
576 int HttpCache::DoomEntry(const std::string
& key
, Transaction
* trans
) {
577 // Need to abandon the ActiveEntry, but any transaction attached to the entry
578 // should not be impacted. Dooming an entry only means that it will no
579 // longer be returned by FindActiveEntry (and it will also be destroyed once
580 // all consumers are finished with the entry).
581 ActiveEntriesMap::iterator it
= active_entries_
.find(key
);
582 if (it
== active_entries_
.end()) {
584 return AsyncDoomEntry(key
, trans
);
587 ActiveEntry
* entry
= it
->second
;
588 active_entries_
.erase(it
);
590 // We keep track of doomed entries so that we can ensure that they are
591 // cleaned up properly when the cache is destroyed.
592 doomed_entries_
.insert(entry
);
594 entry
->disk_entry
->Doom();
595 entry
->doomed
= true;
597 DCHECK(entry
->writer
|| !entry
->readers
.empty() ||
598 entry
->will_process_pending_queue
);
602 int HttpCache::AsyncDoomEntry(const std::string
& key
, Transaction
* trans
) {
603 WorkItem
* item
= new WorkItem(WI_DOOM_ENTRY
, trans
, NULL
);
604 PendingOp
* pending_op
= GetPendingOp(key
);
605 if (pending_op
->writer
) {
606 pending_op
->pending_queue
.push_back(item
);
607 return ERR_IO_PENDING
;
610 DCHECK(pending_op
->pending_queue
.empty());
612 pending_op
->writer
= item
;
613 pending_op
->callback
= base::Bind(&HttpCache::OnPendingOpComplete
,
614 GetWeakPtr(), pending_op
);
616 int rv
= disk_cache_
->DoomEntry(key
, pending_op
->callback
);
617 if (rv
!= ERR_IO_PENDING
) {
618 item
->ClearTransaction();
619 pending_op
->callback
.Run(rv
);
625 void HttpCache::DoomMainEntryForUrl(const GURL
& url
) {
629 HttpRequestInfo temp_info
;
631 temp_info
.method
= "GET";
632 std::string key
= GenerateCacheKey(&temp_info
);
634 // Defer to DoomEntry if there is an active entry, otherwise call
635 // AsyncDoomEntry without triggering a callback.
636 if (active_entries_
.count(key
))
637 DoomEntry(key
, NULL
);
639 AsyncDoomEntry(key
, NULL
);
642 void HttpCache::FinalizeDoomedEntry(ActiveEntry
* entry
) {
643 DCHECK(entry
->doomed
);
644 DCHECK(!entry
->writer
);
645 DCHECK(entry
->readers
.empty());
646 DCHECK(entry
->pending_queue
.empty());
648 ActiveEntriesSet::iterator it
= doomed_entries_
.find(entry
);
649 DCHECK(it
!= doomed_entries_
.end());
650 doomed_entries_
.erase(it
);
655 HttpCache::ActiveEntry
* HttpCache::FindActiveEntry(const std::string
& key
) {
656 ActiveEntriesMap::const_iterator it
= active_entries_
.find(key
);
657 return it
!= active_entries_
.end() ? it
->second
: NULL
;
660 HttpCache::ActiveEntry
* HttpCache::ActivateEntry(
661 disk_cache::Entry
* disk_entry
) {
662 DCHECK(!FindActiveEntry(disk_entry
->GetKey()));
663 ActiveEntry
* entry
= new ActiveEntry(disk_entry
);
664 active_entries_
[disk_entry
->GetKey()] = entry
;
668 void HttpCache::DeactivateEntry(ActiveEntry
* entry
) {
669 DCHECK(!entry
->will_process_pending_queue
);
670 DCHECK(!entry
->doomed
);
671 DCHECK(!entry
->writer
);
672 DCHECK(entry
->disk_entry
);
673 DCHECK(entry
->readers
.empty());
674 DCHECK(entry
->pending_queue
.empty());
676 std::string key
= entry
->disk_entry
->GetKey();
678 return SlowDeactivateEntry(entry
);
680 ActiveEntriesMap::iterator it
= active_entries_
.find(key
);
681 DCHECK(it
!= active_entries_
.end());
682 DCHECK(it
->second
== entry
);
684 active_entries_
.erase(it
);
688 // We don't know this entry's key so we have to find it without it.
689 void HttpCache::SlowDeactivateEntry(ActiveEntry
* entry
) {
690 for (ActiveEntriesMap::iterator it
= active_entries_
.begin();
691 it
!= active_entries_
.end(); ++it
) {
692 if (it
->second
== entry
) {
693 active_entries_
.erase(it
);
700 HttpCache::PendingOp
* HttpCache::GetPendingOp(const std::string
& key
) {
701 DCHECK(!FindActiveEntry(key
));
703 PendingOpsMap::const_iterator it
= pending_ops_
.find(key
);
704 if (it
!= pending_ops_
.end())
707 PendingOp
* operation
= new PendingOp();
708 pending_ops_
[key
] = operation
;
712 void HttpCache::DeletePendingOp(PendingOp
* pending_op
) {
714 if (pending_op
->disk_entry
)
715 key
= pending_op
->disk_entry
->GetKey();
718 PendingOpsMap::iterator it
= pending_ops_
.find(key
);
719 DCHECK(it
!= pending_ops_
.end());
720 pending_ops_
.erase(it
);
722 for (PendingOpsMap::iterator it
= pending_ops_
.begin();
723 it
!= pending_ops_
.end(); ++it
) {
724 if (it
->second
== pending_op
) {
725 pending_ops_
.erase(it
);
730 DCHECK(pending_op
->pending_queue
.empty());
735 int HttpCache::OpenEntry(const std::string
& key
, ActiveEntry
** entry
,
736 Transaction
* trans
) {
737 ActiveEntry
* active_entry
= FindActiveEntry(key
);
739 *entry
= active_entry
;
743 WorkItem
* item
= new WorkItem(WI_OPEN_ENTRY
, trans
, entry
);
744 PendingOp
* pending_op
= GetPendingOp(key
);
745 if (pending_op
->writer
) {
746 pending_op
->pending_queue
.push_back(item
);
747 return ERR_IO_PENDING
;
750 DCHECK(pending_op
->pending_queue
.empty());
752 pending_op
->writer
= item
;
753 pending_op
->callback
= base::Bind(&HttpCache::OnPendingOpComplete
,
754 GetWeakPtr(), pending_op
);
756 int rv
= disk_cache_
->OpenEntry(key
, &(pending_op
->disk_entry
),
757 pending_op
->callback
);
758 if (rv
!= ERR_IO_PENDING
) {
759 item
->ClearTransaction();
760 pending_op
->callback
.Run(rv
);
766 int HttpCache::CreateEntry(const std::string
& key
, ActiveEntry
** entry
,
767 Transaction
* trans
) {
768 if (FindActiveEntry(key
)) {
769 return ERR_CACHE_RACE
;
772 WorkItem
* item
= new WorkItem(WI_CREATE_ENTRY
, trans
, entry
);
773 PendingOp
* pending_op
= GetPendingOp(key
);
774 if (pending_op
->writer
) {
775 pending_op
->pending_queue
.push_back(item
);
776 return ERR_IO_PENDING
;
779 DCHECK(pending_op
->pending_queue
.empty());
781 pending_op
->writer
= item
;
782 pending_op
->callback
= base::Bind(&HttpCache::OnPendingOpComplete
,
783 GetWeakPtr(), pending_op
);
785 int rv
= disk_cache_
->CreateEntry(key
, &(pending_op
->disk_entry
),
786 pending_op
->callback
);
787 if (rv
!= ERR_IO_PENDING
) {
788 item
->ClearTransaction();
789 pending_op
->callback
.Run(rv
);
795 void HttpCache::DestroyEntry(ActiveEntry
* entry
) {
797 FinalizeDoomedEntry(entry
);
799 DeactivateEntry(entry
);
803 int HttpCache::AddTransactionToEntry(ActiveEntry
* entry
, Transaction
* trans
) {
805 DCHECK(entry
->disk_entry
);
807 // We implement a basic reader/writer lock for the disk cache entry. If
808 // there is already a writer, then everyone has to wait for the writer to
809 // finish before they can access the cache entry. There can be multiple
812 // NOTE: If the transaction can only write, then the entry should not be in
813 // use (since any existing entry should have already been doomed).
815 if (entry
->writer
|| entry
->will_process_pending_queue
) {
816 entry
->pending_queue
.push_back(trans
);
817 return ERR_IO_PENDING
;
820 if (trans
->mode() & Transaction::WRITE
) {
821 // transaction needs exclusive access to the entry
822 if (entry
->readers
.empty()) {
823 entry
->writer
= trans
;
825 entry
->pending_queue
.push_back(trans
);
826 return ERR_IO_PENDING
;
829 // transaction needs read access to the entry
830 entry
->readers
.push_back(trans
);
833 // We do this before calling EntryAvailable to force any further calls to
834 // AddTransactionToEntry to add their transaction to the pending queue, which
835 // ensures FIFO ordering.
836 if (!entry
->writer
&& !entry
->pending_queue
.empty())
837 ProcessPendingQueue(entry
);
842 void HttpCache::DoneWithEntry(ActiveEntry
* entry
, Transaction
* trans
,
844 // If we already posted a task to move on to the next transaction and this was
845 // the writer, there is nothing to cancel.
846 if (entry
->will_process_pending_queue
&& entry
->readers
.empty())
850 DCHECK(trans
== entry
->writer
);
852 // Assume there was a failure.
853 bool success
= false;
855 DCHECK(entry
->disk_entry
);
856 // This is a successful operation in the sense that we want to keep the
858 success
= trans
->AddTruncatedFlag();
859 // The previous operation may have deleted the entry.
863 DoneWritingToEntry(entry
, success
);
865 DoneReadingFromEntry(entry
, trans
);
869 void HttpCache::DoneWritingToEntry(ActiveEntry
* entry
, bool success
) {
870 DCHECK(entry
->readers
.empty());
872 entry
->writer
= NULL
;
875 ProcessPendingQueue(entry
);
877 DCHECK(!entry
->will_process_pending_queue
);
879 // We failed to create this entry.
880 TransactionList pending_queue
;
881 pending_queue
.swap(entry
->pending_queue
);
883 entry
->disk_entry
->Doom();
886 // We need to do something about these pending entries, which now need to
887 // be added to a new entry.
888 while (!pending_queue
.empty()) {
889 // ERR_CACHE_RACE causes the transaction to restart the whole process.
890 pending_queue
.front()->io_callback().Run(ERR_CACHE_RACE
);
891 pending_queue
.pop_front();
896 void HttpCache::DoneReadingFromEntry(ActiveEntry
* entry
, Transaction
* trans
) {
897 DCHECK(!entry
->writer
);
899 TransactionList::iterator it
=
900 std::find(entry
->readers
.begin(), entry
->readers
.end(), trans
);
901 DCHECK(it
!= entry
->readers
.end());
903 entry
->readers
.erase(it
);
905 ProcessPendingQueue(entry
);
908 void HttpCache::ConvertWriterToReader(ActiveEntry
* entry
) {
909 DCHECK(entry
->writer
);
910 DCHECK(entry
->writer
->mode() == Transaction::READ_WRITE
);
911 DCHECK(entry
->readers
.empty());
913 Transaction
* trans
= entry
->writer
;
915 entry
->writer
= NULL
;
916 entry
->readers
.push_back(trans
);
918 ProcessPendingQueue(entry
);
921 LoadState
HttpCache::GetLoadStateForPendingTransaction(
922 const Transaction
* trans
) {
923 ActiveEntriesMap::const_iterator i
= active_entries_
.find(trans
->key());
924 if (i
== active_entries_
.end()) {
925 // If this is really a pending transaction, and it is not part of
926 // active_entries_, we should be creating the backend or the entry.
927 return LOAD_STATE_WAITING_FOR_CACHE
;
930 Transaction
* writer
= i
->second
->writer
;
931 return writer
? writer
->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE
;
934 void HttpCache::RemovePendingTransaction(Transaction
* trans
) {
935 ActiveEntriesMap::const_iterator i
= active_entries_
.find(trans
->key());
937 if (i
!= active_entries_
.end())
938 found
= RemovePendingTransactionFromEntry(i
->second
, trans
);
943 if (building_backend_
) {
944 PendingOpsMap::const_iterator j
= pending_ops_
.find(std::string());
945 if (j
!= pending_ops_
.end())
946 found
= RemovePendingTransactionFromPendingOp(j
->second
, trans
);
952 PendingOpsMap::const_iterator j
= pending_ops_
.find(trans
->key());
953 if (j
!= pending_ops_
.end())
954 found
= RemovePendingTransactionFromPendingOp(j
->second
, trans
);
959 ActiveEntriesSet::iterator k
= doomed_entries_
.begin();
960 for (; k
!= doomed_entries_
.end() && !found
; ++k
)
961 found
= RemovePendingTransactionFromEntry(*k
, trans
);
963 DCHECK(found
) << "Pending transaction not found";
966 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry
* entry
,
967 Transaction
* trans
) {
968 TransactionList
& pending_queue
= entry
->pending_queue
;
970 TransactionList::iterator j
=
971 find(pending_queue
.begin(), pending_queue
.end(), trans
);
972 if (j
== pending_queue
.end())
975 pending_queue
.erase(j
);
979 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp
* pending_op
,
980 Transaction
* trans
) {
981 if (pending_op
->writer
->Matches(trans
)) {
982 pending_op
->writer
->ClearTransaction();
983 pending_op
->writer
->ClearEntry();
986 WorkItemList
& pending_queue
= pending_op
->pending_queue
;
988 WorkItemList::iterator it
= pending_queue
.begin();
989 for (; it
!= pending_queue
.end(); ++it
) {
990 if ((*it
)->Matches(trans
)) {
992 pending_queue
.erase(it
);
999 void HttpCache::SetupQuicServerInfoFactory(HttpNetworkSession
* session
) {
1001 !session
->quic_stream_factory()->has_quic_server_info_factory()) {
1002 DCHECK(!quic_server_info_factory_
);
1003 quic_server_info_factory_
.reset(new QuicServerInfoFactoryAdaptor(this));
1004 session
->quic_stream_factory()->set_quic_server_info_factory(
1005 quic_server_info_factory_
.get());
1009 void HttpCache::ProcessPendingQueue(ActiveEntry
* entry
) {
1010 // Multiple readers may finish with an entry at once, so we want to batch up
1011 // calls to OnProcessPendingQueue. This flag also tells us that we should
1012 // not delete the entry before OnProcessPendingQueue runs.
1013 if (entry
->will_process_pending_queue
)
1015 entry
->will_process_pending_queue
= true;
1017 base::ThreadTaskRunnerHandle::Get()->PostTask(
1019 base::Bind(&HttpCache::OnProcessPendingQueue
, GetWeakPtr(), entry
));
1022 void HttpCache::OnProcessPendingQueue(ActiveEntry
* entry
) {
1023 entry
->will_process_pending_queue
= false;
1024 DCHECK(!entry
->writer
);
1026 // If no one is interested in this entry, then we can deactivate it.
1027 if (entry
->pending_queue
.empty()) {
1028 if (entry
->readers
.empty())
1029 DestroyEntry(entry
);
1033 // Promote next transaction from the pending queue.
1034 Transaction
* next
= entry
->pending_queue
.front();
1035 if ((next
->mode() & Transaction::WRITE
) && !entry
->readers
.empty())
1036 return; // Have to wait.
1038 entry
->pending_queue
.erase(entry
->pending_queue
.begin());
1040 int rv
= AddTransactionToEntry(entry
, next
);
1041 if (rv
!= ERR_IO_PENDING
) {
1042 next
->io_callback().Run(rv
);
1046 void HttpCache::OnIOComplete(int result
, PendingOp
* pending_op
) {
1047 WorkItemOperation op
= pending_op
->writer
->operation();
1049 // Completing the creation of the backend is simpler than the other cases.
1050 if (op
== WI_CREATE_BACKEND
)
1051 return OnBackendCreated(result
, pending_op
);
1053 scoped_ptr
<WorkItem
> item(pending_op
->writer
);
1054 bool fail_requests
= false;
1056 ActiveEntry
* entry
= NULL
;
1059 if (op
== WI_DOOM_ENTRY
) {
1060 // Anything after a Doom has to be restarted.
1061 fail_requests
= true;
1062 } else if (item
->IsValid()) {
1063 key
= pending_op
->disk_entry
->GetKey();
1064 entry
= ActivateEntry(pending_op
->disk_entry
);
1066 // The writer transaction is gone.
1067 if (op
== WI_CREATE_ENTRY
)
1068 pending_op
->disk_entry
->Doom();
1069 pending_op
->disk_entry
->Close();
1070 pending_op
->disk_entry
= NULL
;
1071 fail_requests
= true;
1075 // We are about to notify a bunch of transactions, and they may decide to
1076 // re-issue a request (or send a different one). If we don't delete
1077 // pending_op, the new request will be appended to the end of the list, and
1078 // we'll see it again from this point before it has a chance to complete (and
1079 // we'll be messing out the request order). The down side is that if for some
1080 // reason notifying request A ends up cancelling request B (for the same key),
1081 // we won't find request B anywhere (because it would be in a local variable
1082 // here) and that's bad. If there is a chance for that to happen, we'll have
1083 // to move the callback used to be a CancelableCallback. By the way, for this
1084 // to happen the action (to cancel B) has to be synchronous to the
1085 // notification for request A.
1086 WorkItemList pending_items
;
1087 pending_items
.swap(pending_op
->pending_queue
);
1088 DeletePendingOp(pending_op
);
1090 item
->NotifyTransaction(result
, entry
);
1092 while (!pending_items
.empty()) {
1093 item
.reset(pending_items
.front());
1094 pending_items
.pop_front();
1096 if (item
->operation() == WI_DOOM_ENTRY
) {
1097 // A queued doom request is always a race.
1098 fail_requests
= true;
1099 } else if (result
== OK
) {
1100 entry
= FindActiveEntry(key
);
1102 fail_requests
= true;
1105 if (fail_requests
) {
1106 item
->NotifyTransaction(ERR_CACHE_RACE
, NULL
);
1110 if (item
->operation() == WI_CREATE_ENTRY
) {
1112 // A second Create request, but the first request succeeded.
1113 item
->NotifyTransaction(ERR_CACHE_CREATE_FAILURE
, NULL
);
1115 if (op
!= WI_CREATE_ENTRY
) {
1116 // Failed Open followed by a Create.
1117 item
->NotifyTransaction(ERR_CACHE_RACE
, NULL
);
1118 fail_requests
= true;
1120 item
->NotifyTransaction(result
, entry
);
1124 if (op
== WI_CREATE_ENTRY
&& result
!= OK
) {
1125 // Failed Create followed by an Open.
1126 item
->NotifyTransaction(ERR_CACHE_RACE
, NULL
);
1127 fail_requests
= true;
1129 item
->NotifyTransaction(result
, entry
);
1136 void HttpCache::OnPendingOpComplete(const base::WeakPtr
<HttpCache
>& cache
,
1137 PendingOp
* pending_op
,
1140 cache
->OnIOComplete(rv
, pending_op
);
1142 // The callback was cancelled so we should delete the pending_op that
1143 // was used with this callback.
1148 void HttpCache::OnBackendCreated(int result
, PendingOp
* pending_op
) {
1149 scoped_ptr
<WorkItem
> item(pending_op
->writer
);
1150 WorkItemOperation op
= item
->operation();
1151 DCHECK_EQ(WI_CREATE_BACKEND
, op
);
1153 // We don't need the callback anymore.
1154 pending_op
->callback
.Reset();
1156 if (backend_factory_
.get()) {
1157 // We may end up calling OnBackendCreated multiple times if we have pending
1158 // work items. The first call saves the backend and releases the factory,
1159 // and the last call clears building_backend_.
1160 backend_factory_
.reset(); // Reclaim memory.
1162 disk_cache_
= pending_op
->backend
.Pass();
1164 cert_cache_
.reset(new DiskBasedCertCache(disk_cache_
.get()));
1168 if (!pending_op
->pending_queue
.empty()) {
1169 WorkItem
* pending_item
= pending_op
->pending_queue
.front();
1170 pending_op
->pending_queue
.pop_front();
1171 DCHECK_EQ(WI_CREATE_BACKEND
, pending_item
->operation());
1173 // We want to process a single callback at a time, because the cache may
1174 // go away from the callback.
1175 pending_op
->writer
= pending_item
;
1177 base::ThreadTaskRunnerHandle::Get()->PostTask(
1178 FROM_HERE
, base::Bind(&HttpCache::OnBackendCreated
, GetWeakPtr(),
1179 result
, pending_op
));
1181 building_backend_
= false;
1182 DeletePendingOp(pending_op
);
1185 // The cache may be gone when we return from the callback.
1186 if (!item
->DoCallback(result
, disk_cache_
.get()))
1187 item
->NotifyTransaction(result
, NULL
);