Make Ctrl + T from apps focus the new tab's omnibox on Linux and ChromeOS.
[chromium-blink-merge.git] / net / http / http_cache.cc
blobb5a79a3a9bfaa019fe0b4df37947e00b22f22403
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"
7 #include <algorithm>
9 #include "base/compiler_specific.h"
11 #if defined(OS_POSIX)
12 #include <unistd.h>
13 #endif
15 #include "base/bind.h"
16 #include "base/bind_helpers.h"
17 #include "base/callback.h"
18 #include "base/files/file_util.h"
19 #include "base/format_macros.h"
20 #include "base/location.h"
21 #include "base/memory/ref_counted.h"
22 #include "base/message_loop/message_loop.h"
23 #include "base/metrics/field_trial.h"
24 #include "base/metrics/histogram.h"
25 #include "base/pickle.h"
26 #include "base/stl_util.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/threading/worker_pool.h"
31 #include "base/time/default_clock.h"
32 #include "base/time/time.h"
33 #include "net/base/cache_type.h"
34 #include "net/base/io_buffer.h"
35 #include "net/base/load_flags.h"
36 #include "net/base/net_errors.h"
37 #include "net/base/network_delegate.h"
38 #include "net/base/upload_data_stream.h"
39 #include "net/disk_cache/disk_cache.h"
40 #include "net/http/disk_based_cert_cache.h"
41 #include "net/http/disk_cache_based_quic_server_info.h"
42 #include "net/http/http_cache_transaction.h"
43 #include "net/http/http_network_layer.h"
44 #include "net/http/http_network_session.h"
45 #include "net/http/http_request_info.h"
46 #include "net/http/http_response_headers.h"
47 #include "net/http/http_response_info.h"
48 #include "net/http/http_util.h"
49 #include "net/quic/crypto/quic_server_info.h"
51 namespace {
53 bool UseCertCache() {
54 return base::FieldTrialList::FindFullName("CertCacheTrial") ==
55 "ExperimentGroup";
58 } // namespace
60 namespace net {
62 HttpCache::DefaultBackend::DefaultBackend(
63 CacheType type,
64 BackendType backend_type,
65 const base::FilePath& path,
66 int max_bytes,
67 const scoped_refptr<base::SingleThreadTaskRunner>& thread)
68 : type_(type),
69 backend_type_(backend_type),
70 path_(path),
71 max_bytes_(max_bytes),
72 thread_(thread) {
75 HttpCache::DefaultBackend::~DefaultBackend() {}
77 // static
78 HttpCache::BackendFactory* HttpCache::DefaultBackend::InMemory(int max_bytes) {
79 return new DefaultBackend(MEMORY_CACHE, CACHE_BACKEND_DEFAULT,
80 base::FilePath(), max_bytes, NULL);
83 int HttpCache::DefaultBackend::CreateBackend(
84 NetLog* net_log, scoped_ptr<disk_cache::Backend>* backend,
85 const CompletionCallback& callback) {
86 DCHECK_GE(max_bytes_, 0);
87 return disk_cache::CreateCacheBackend(type_,
88 backend_type_,
89 path_,
90 max_bytes_,
91 true,
92 thread_,
93 net_log,
94 backend,
95 callback);
98 //-----------------------------------------------------------------------------
100 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
101 : disk_entry(entry),
102 writer(NULL),
103 will_process_pending_queue(false),
104 doomed(false) {
107 HttpCache::ActiveEntry::~ActiveEntry() {
108 if (disk_entry) {
109 disk_entry->Close();
110 disk_entry = NULL;
114 //-----------------------------------------------------------------------------
116 // This structure keeps track of work items that are attempting to create or
117 // open cache entries or the backend itself.
118 struct HttpCache::PendingOp {
119 PendingOp() : disk_entry(NULL), writer(NULL) {}
120 ~PendingOp() {}
122 disk_cache::Entry* disk_entry;
123 scoped_ptr<disk_cache::Backend> backend;
124 WorkItem* writer;
125 CompletionCallback callback; // BackendCallback.
126 WorkItemList pending_queue;
129 //-----------------------------------------------------------------------------
131 // The type of operation represented by a work item.
132 enum WorkItemOperation {
133 WI_CREATE_BACKEND,
134 WI_OPEN_ENTRY,
135 WI_CREATE_ENTRY,
136 WI_DOOM_ENTRY
139 // A work item encapsulates a single request to the backend with all the
140 // information needed to complete that request.
141 class HttpCache::WorkItem {
142 public:
143 WorkItem(WorkItemOperation operation, Transaction* trans, ActiveEntry** entry)
144 : operation_(operation),
145 trans_(trans),
146 entry_(entry),
147 backend_(NULL) {}
148 WorkItem(WorkItemOperation operation,
149 Transaction* trans,
150 const CompletionCallback& cb,
151 disk_cache::Backend** backend)
152 : operation_(operation),
153 trans_(trans),
154 entry_(NULL),
155 callback_(cb),
156 backend_(backend) {}
157 ~WorkItem() {}
159 // Calls back the transaction with the result of the operation.
160 void NotifyTransaction(int result, ActiveEntry* entry) {
161 DCHECK(!entry || entry->disk_entry);
162 if (entry_)
163 *entry_ = entry;
164 if (trans_)
165 trans_->io_callback().Run(result);
168 // Notifies the caller about the operation completion. Returns true if the
169 // callback was invoked.
170 bool DoCallback(int result, disk_cache::Backend* backend) {
171 if (backend_)
172 *backend_ = backend;
173 if (!callback_.is_null()) {
174 callback_.Run(result);
175 return true;
177 return false;
180 WorkItemOperation operation() { return operation_; }
181 void ClearTransaction() { trans_ = NULL; }
182 void ClearEntry() { entry_ = NULL; }
183 void ClearCallback() { callback_.Reset(); }
184 bool Matches(Transaction* trans) const { return trans == trans_; }
185 bool IsValid() const { return trans_ || entry_ || !callback_.is_null(); }
187 private:
188 WorkItemOperation operation_;
189 Transaction* trans_;
190 ActiveEntry** entry_;
191 CompletionCallback callback_; // User callback.
192 disk_cache::Backend** backend_;
195 //-----------------------------------------------------------------------------
197 // This class encapsulates a transaction whose only purpose is to write metadata
198 // to a given entry.
199 class HttpCache::MetadataWriter {
200 public:
201 explicit MetadataWriter(HttpCache::Transaction* trans)
202 : transaction_(trans),
203 verified_(false),
204 buf_len_(0) {
207 ~MetadataWriter() {}
209 // Implements the bulk of HttpCache::WriteMetadata.
210 void Write(const GURL& url,
211 base::Time expected_response_time,
212 IOBuffer* buf,
213 int buf_len);
215 private:
216 void VerifyResponse(int result);
217 void SelfDestroy();
218 void OnIOComplete(int result);
220 scoped_ptr<HttpCache::Transaction> transaction_;
221 bool verified_;
222 scoped_refptr<IOBuffer> buf_;
223 int buf_len_;
224 base::Time expected_response_time_;
225 HttpRequestInfo request_info_;
226 DISALLOW_COPY_AND_ASSIGN(MetadataWriter);
229 void HttpCache::MetadataWriter::Write(const GURL& url,
230 base::Time expected_response_time,
231 IOBuffer* buf,
232 int buf_len) {
233 DCHECK_GT(buf_len, 0);
234 DCHECK(buf);
235 DCHECK(buf->data());
236 request_info_.url = url;
237 request_info_.method = "GET";
238 request_info_.load_flags = LOAD_ONLY_FROM_CACHE;
240 expected_response_time_ = expected_response_time;
241 buf_ = buf;
242 buf_len_ = buf_len;
243 verified_ = false;
245 int rv = transaction_->Start(
246 &request_info_,
247 base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this)),
248 BoundNetLog());
249 if (rv != ERR_IO_PENDING)
250 VerifyResponse(rv);
253 void HttpCache::MetadataWriter::VerifyResponse(int result) {
254 verified_ = true;
255 if (result != OK)
256 return SelfDestroy();
258 const HttpResponseInfo* response_info = transaction_->GetResponseInfo();
259 DCHECK(response_info->was_cached);
260 if (response_info->response_time != expected_response_time_)
261 return SelfDestroy();
263 result = transaction_->WriteMetadata(
264 buf_.get(),
265 buf_len_,
266 base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this)));
267 if (result != ERR_IO_PENDING)
268 SelfDestroy();
271 void HttpCache::MetadataWriter::SelfDestroy() {
272 delete this;
275 void HttpCache::MetadataWriter::OnIOComplete(int result) {
276 if (!verified_)
277 return VerifyResponse(result);
278 SelfDestroy();
281 //-----------------------------------------------------------------------------
283 class HttpCache::QuicServerInfoFactoryAdaptor : public QuicServerInfoFactory {
284 public:
285 explicit QuicServerInfoFactoryAdaptor(HttpCache* http_cache)
286 : http_cache_(http_cache) {
289 QuicServerInfo* GetForServer(const QuicServerId& server_id) override {
290 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_);
293 private:
294 HttpCache* const http_cache_;
297 //-----------------------------------------------------------------------------
299 class HttpCache::AsyncValidation {
300 public:
301 AsyncValidation(const HttpRequestInfo& original_request, HttpCache* cache)
302 : request_(original_request), cache_(cache) {}
303 ~AsyncValidation() {}
305 void Start(const BoundNetLog& net_log,
306 scoped_ptr<Transaction> transaction,
307 NetworkDelegate* network_delegate);
309 private:
310 void OnStarted(int result);
311 void DoRead();
312 void OnRead(int result);
314 // Terminate this request with net error code |result|. Logs the transaction
315 // result and asks HttpCache to delete this object.
316 // If there was a client or server certificate error, it cannot be recovered
317 // asynchronously, so we need to prevent future attempts to asynchronously
318 // fetch the resource. In this case, the cache entry is doomed.
319 void Terminate(int result);
321 HttpRequestInfo request_;
322 scoped_refptr<IOBuffer> buf_;
323 CompletionCallback read_callback_;
324 scoped_ptr<Transaction> transaction_;
325 base::Time start_time_;
327 // The HttpCache object owns this object. This object is always deleted before
328 // the pointer to the cache becomes invalid.
329 HttpCache* cache_;
331 DISALLOW_COPY_AND_ASSIGN(AsyncValidation);
334 void HttpCache::AsyncValidation::Start(const BoundNetLog& net_log,
335 scoped_ptr<Transaction> transaction,
336 NetworkDelegate* network_delegate) {
337 transaction_ = transaction.Pass();
338 if (network_delegate) {
339 // This code is necessary to enable async transactions to pass over the
340 // data-reduction proxy. This is a violation of the "once-and-only-once"
341 // principle, since it copies code from URLRequestHttpJob. We cannot use the
342 // original callback passed to HttpCache::Transaction by URLRequestHttpJob
343 // as it will only be valid as long as the URLRequestHttpJob object is
344 // alive, and that object will be deleted as soon as the synchronous request
345 // completes.
347 // This code is also an encapsulation violation. We are exploiting the fact
348 // that the |request| parameter to NotifyBeforeSendProxyHeaders() is never
349 // actually used for anything, and so can be NULL.
351 // TODO(ricea): Do this better.
352 transaction_->SetBeforeProxyHeadersSentCallback(
353 base::Bind(&NetworkDelegate::NotifyBeforeSendProxyHeaders,
354 base::Unretained(network_delegate),
355 static_cast<URLRequest*>(NULL)));
356 // The above use of base::Unretained is safe because the NetworkDelegate has
357 // to live at least as long as the HttpNetworkSession which has to live as
358 // least as long as the HttpNetworkLayer which has to live at least as long
359 // this HttpCache object.
362 DCHECK_EQ(0, request_.load_flags & LOAD_ASYNC_REVALIDATION);
363 request_.load_flags |= LOAD_ASYNC_REVALIDATION;
364 start_time_ = cache_->clock()->Now();
365 // This use of base::Unretained is safe because |transaction_| is owned by
366 // this object.
367 read_callback_ = base::Bind(&AsyncValidation::OnRead, base::Unretained(this));
368 // This use of base::Unretained is safe as above.
369 int rv = transaction_->Start(
370 &request_,
371 base::Bind(&AsyncValidation::OnStarted, base::Unretained(this)),
372 net_log);
374 if (rv == ERR_IO_PENDING)
375 return;
377 OnStarted(rv);
380 void HttpCache::AsyncValidation::OnStarted(int result) {
381 if (result != OK) {
382 DVLOG(1) << "Asynchronous transaction start failed for " << request_.url;
383 Terminate(result);
384 return;
387 while (transaction_->IsReadyToRestartForAuth()) {
388 // This code is based on URLRequestHttpJob::RestartTransactionWithAuth,
389 // however when we do this here cookies on the response will not be
390 // stored. Fortunately only a tiny number of sites set cookies on 401
391 // responses, and none of them use stale-while-revalidate.
392 result = transaction_->RestartWithAuth(
393 AuthCredentials(),
394 base::Bind(&AsyncValidation::OnStarted, base::Unretained(this)));
395 if (result == ERR_IO_PENDING)
396 return;
397 if (result != OK) {
398 DVLOG(1) << "Synchronous transaction restart with auth failed for "
399 << request_.url;
400 Terminate(result);
401 return;
405 DoRead();
408 void HttpCache::AsyncValidation::DoRead() {
409 const size_t kBufSize = 4096;
410 if (!buf_.get())
411 buf_ = new IOBuffer(kBufSize);
413 int rv = 0;
414 do {
415 rv = transaction_->Read(buf_.get(), kBufSize, read_callback_);
416 } while (rv > 0);
418 if (rv == ERR_IO_PENDING)
419 return;
421 OnRead(rv);
424 void HttpCache::AsyncValidation::OnRead(int result) {
425 if (result > 0) {
426 DoRead();
427 return;
429 Terminate(result);
432 void HttpCache::AsyncValidation::Terminate(int result) {
433 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED || IsCertificateError(result)) {
434 // We should not attempt to access this resource asynchronously again until
435 // the certificate problem has been resolved.
436 // TODO(ricea): For ERR_SSL_CLIENT_AUTH_CERT_NEEDED, mark the entry as
437 // requiring synchronous revalidation rather than just deleting it. Other
438 // certificate errors cause the resource to be considered uncacheable
439 // anyway.
440 cache_->DoomEntry(transaction_->key(), transaction_.get());
442 base::TimeDelta duration = cache_->clock()->Now() - start_time_;
443 UMA_HISTOGRAM_TIMES("HttpCache.AsyncValidationDuration", duration);
444 transaction_->net_log().EndEventWithNetErrorCode(
445 NetLog::TYPE_ASYNC_REVALIDATION, result);
446 cache_->DeleteAsyncValidation(cache_->GenerateCacheKey(&request_));
447 // |this| is deleted.
450 //-----------------------------------------------------------------------------
451 HttpCache::HttpCache(const HttpNetworkSession::Params& params,
452 BackendFactory* backend_factory)
453 : net_log_(params.net_log),
454 backend_factory_(backend_factory),
455 building_backend_(false),
456 bypass_lock_for_test_(false),
457 fail_conditionalization_for_test_(false),
458 use_stale_while_revalidate_(params.use_stale_while_revalidate),
459 mode_(NORMAL),
460 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))),
461 clock_(new base::DefaultClock()),
462 weak_factory_(this) {
463 SetupQuicServerInfoFactory(network_layer_->GetSession());
467 // This call doesn't change the shared |session|'s QuicServerInfoFactory because
468 // |session| is shared.
469 HttpCache::HttpCache(HttpNetworkSession* session,
470 BackendFactory* backend_factory)
471 : net_log_(session->net_log()),
472 backend_factory_(backend_factory),
473 building_backend_(false),
474 bypass_lock_for_test_(false),
475 fail_conditionalization_for_test_(false),
476 use_stale_while_revalidate_(session->params().use_stale_while_revalidate),
477 mode_(NORMAL),
478 network_layer_(new HttpNetworkLayer(session)),
479 clock_(new base::DefaultClock()),
480 weak_factory_(this) {
483 HttpCache::HttpCache(HttpTransactionFactory* network_layer,
484 NetLog* net_log,
485 BackendFactory* backend_factory)
486 : net_log_(net_log),
487 backend_factory_(backend_factory),
488 building_backend_(false),
489 bypass_lock_for_test_(false),
490 fail_conditionalization_for_test_(false),
491 use_stale_while_revalidate_(false),
492 mode_(NORMAL),
493 network_layer_(network_layer),
494 clock_(new base::DefaultClock()),
495 weak_factory_(this) {
496 SetupQuicServerInfoFactory(network_layer_->GetSession());
497 HttpNetworkSession* session = network_layer_->GetSession();
498 if (session)
499 use_stale_while_revalidate_ = session->params().use_stale_while_revalidate;
502 HttpCache::~HttpCache() {
503 // Transactions should see an invalid cache after this point; otherwise they
504 // could see an inconsistent object (half destroyed).
505 weak_factory_.InvalidateWeakPtrs();
507 // If we have any active entries remaining, then we need to deactivate them.
508 // We may have some pending calls to OnProcessPendingQueue, but since those
509 // won't run (due to our destruction), we can simply ignore the corresponding
510 // will_process_pending_queue flag.
511 while (!active_entries_.empty()) {
512 ActiveEntry* entry = active_entries_.begin()->second;
513 entry->will_process_pending_queue = false;
514 entry->pending_queue.clear();
515 entry->readers.clear();
516 entry->writer = NULL;
517 DeactivateEntry(entry);
520 STLDeleteElements(&doomed_entries_);
521 STLDeleteValues(&async_validations_);
523 // Before deleting pending_ops_, we have to make sure that the disk cache is
524 // done with said operations, or it will attempt to use deleted data.
525 cert_cache_.reset();
526 disk_cache_.reset();
528 PendingOpsMap::iterator pending_it = pending_ops_.begin();
529 for (; pending_it != pending_ops_.end(); ++pending_it) {
530 // We are not notifying the transactions about the cache going away, even
531 // though they are waiting for a callback that will never fire.
532 PendingOp* pending_op = pending_it->second;
533 delete pending_op->writer;
534 bool delete_pending_op = true;
535 if (building_backend_) {
536 // If we don't have a backend, when its construction finishes it will
537 // deliver the callbacks.
538 if (!pending_op->callback.is_null()) {
539 // If not null, the callback will delete the pending operation later.
540 delete_pending_op = false;
542 } else {
543 pending_op->callback.Reset();
546 STLDeleteElements(&pending_op->pending_queue);
547 if (delete_pending_op)
548 delete pending_op;
552 int HttpCache::GetBackend(disk_cache::Backend** backend,
553 const CompletionCallback& callback) {
554 DCHECK(!callback.is_null());
556 if (disk_cache_.get()) {
557 *backend = disk_cache_.get();
558 return OK;
561 return CreateBackend(backend, callback);
564 disk_cache::Backend* HttpCache::GetCurrentBackend() const {
565 return disk_cache_.get();
568 // static
569 bool HttpCache::ParseResponseInfo(const char* data, int len,
570 HttpResponseInfo* response_info,
571 bool* response_truncated) {
572 Pickle pickle(data, len);
573 return response_info->InitFromPickle(pickle, response_truncated);
576 void HttpCache::WriteMetadata(const GURL& url,
577 RequestPriority priority,
578 base::Time expected_response_time,
579 IOBuffer* buf,
580 int buf_len) {
581 if (!buf_len)
582 return;
584 // Do lazy initialization of disk cache if needed.
585 if (!disk_cache_.get()) {
586 // We don't care about the result.
587 CreateBackend(NULL, CompletionCallback());
590 HttpCache::Transaction* trans =
591 new HttpCache::Transaction(priority, this);
592 MetadataWriter* writer = new MetadataWriter(trans);
594 // The writer will self destruct when done.
595 writer->Write(url, expected_response_time, buf, buf_len);
598 void HttpCache::CloseAllConnections() {
599 HttpNetworkSession* session = GetSession();
600 if (session)
601 session->CloseAllConnections();
604 void HttpCache::CloseIdleConnections() {
605 HttpNetworkSession* session = GetSession();
606 if (session)
607 session->CloseIdleConnections();
610 void HttpCache::OnExternalCacheHit(const GURL& url,
611 const std::string& http_method) {
612 if (!disk_cache_.get() || mode_ == DISABLE)
613 return;
615 HttpRequestInfo request_info;
616 request_info.url = url;
617 request_info.method = http_method;
618 std::string key = GenerateCacheKey(&request_info);
619 disk_cache_->OnExternalCacheHit(key);
622 int HttpCache::CreateTransaction(RequestPriority priority,
623 scoped_ptr<HttpTransaction>* trans) {
624 // Do lazy initialization of disk cache if needed.
625 if (!disk_cache_.get()) {
626 // We don't care about the result.
627 CreateBackend(NULL, CompletionCallback());
630 HttpCache::Transaction* transaction =
631 new HttpCache::Transaction(priority, this);
632 if (bypass_lock_for_test_)
633 transaction->BypassLockForTest();
634 if (fail_conditionalization_for_test_)
635 transaction->FailConditionalizationForTest();
637 trans->reset(transaction);
638 return OK;
641 HttpCache* HttpCache::GetCache() {
642 return this;
645 HttpNetworkSession* HttpCache::GetSession() {
646 return network_layer_->GetSession();
649 scoped_ptr<HttpTransactionFactory>
650 HttpCache::SetHttpNetworkTransactionFactoryForTesting(
651 scoped_ptr<HttpTransactionFactory> new_network_layer) {
652 scoped_ptr<HttpTransactionFactory> old_network_layer(network_layer_.Pass());
653 network_layer_ = new_network_layer.Pass();
654 return old_network_layer.Pass();
657 //-----------------------------------------------------------------------------
659 int HttpCache::CreateBackend(disk_cache::Backend** backend,
660 const CompletionCallback& callback) {
661 if (!backend_factory_.get())
662 return ERR_FAILED;
664 building_backend_ = true;
666 scoped_ptr<WorkItem> item(new WorkItem(WI_CREATE_BACKEND, NULL, callback,
667 backend));
669 // This is the only operation that we can do that is not related to any given
670 // entry, so we use an empty key for it.
671 PendingOp* pending_op = GetPendingOp(std::string());
672 if (pending_op->writer) {
673 if (!callback.is_null())
674 pending_op->pending_queue.push_back(item.release());
675 return ERR_IO_PENDING;
678 DCHECK(pending_op->pending_queue.empty());
680 pending_op->writer = item.release();
681 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
682 GetWeakPtr(), pending_op);
684 int rv = backend_factory_->CreateBackend(net_log_, &pending_op->backend,
685 pending_op->callback);
686 if (rv != ERR_IO_PENDING) {
687 pending_op->writer->ClearCallback();
688 pending_op->callback.Run(rv);
691 return rv;
694 int HttpCache::GetBackendForTransaction(Transaction* trans) {
695 if (disk_cache_.get())
696 return OK;
698 if (!building_backend_)
699 return ERR_FAILED;
701 WorkItem* item =
702 new WorkItem(WI_CREATE_BACKEND, trans, CompletionCallback(), NULL);
703 PendingOp* pending_op = GetPendingOp(std::string());
704 DCHECK(pending_op->writer);
705 pending_op->pending_queue.push_back(item);
706 return ERR_IO_PENDING;
709 // Generate a key that can be used inside the cache.
710 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
711 // Strip out the reference, username, and password sections of the URL.
712 std::string url = HttpUtil::SpecForRequest(request->url);
714 DCHECK_NE(DISABLE, mode_);
715 // No valid URL can begin with numerals, so we should not have to worry
716 // about collisions with normal URLs.
717 if (request->upload_data_stream &&
718 request->upload_data_stream->identifier()) {
719 url.insert(0,
720 base::StringPrintf("%" PRId64 "/",
721 request->upload_data_stream->identifier()));
723 return url;
726 void HttpCache::DoomActiveEntry(const std::string& key) {
727 ActiveEntriesMap::iterator it = active_entries_.find(key);
728 if (it == active_entries_.end())
729 return;
731 // This is not a performance critical operation, this is handling an error
732 // condition so it is OK to look up the entry again.
733 int rv = DoomEntry(key, NULL);
734 DCHECK_EQ(OK, rv);
737 int HttpCache::DoomEntry(const std::string& key, Transaction* trans) {
738 // Need to abandon the ActiveEntry, but any transaction attached to the entry
739 // should not be impacted. Dooming an entry only means that it will no
740 // longer be returned by FindActiveEntry (and it will also be destroyed once
741 // all consumers are finished with the entry).
742 ActiveEntriesMap::iterator it = active_entries_.find(key);
743 if (it == active_entries_.end()) {
744 DCHECK(trans);
745 return AsyncDoomEntry(key, trans);
748 ActiveEntry* entry = it->second;
749 active_entries_.erase(it);
751 // We keep track of doomed entries so that we can ensure that they are
752 // cleaned up properly when the cache is destroyed.
753 doomed_entries_.insert(entry);
755 entry->disk_entry->Doom();
756 entry->doomed = true;
758 DCHECK(entry->writer || !entry->readers.empty() ||
759 entry->will_process_pending_queue);
760 return OK;
763 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
764 WorkItem* item = new WorkItem(WI_DOOM_ENTRY, trans, NULL);
765 PendingOp* pending_op = GetPendingOp(key);
766 if (pending_op->writer) {
767 pending_op->pending_queue.push_back(item);
768 return ERR_IO_PENDING;
771 DCHECK(pending_op->pending_queue.empty());
773 pending_op->writer = item;
774 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
775 GetWeakPtr(), pending_op);
777 int rv = disk_cache_->DoomEntry(key, pending_op->callback);
778 if (rv != ERR_IO_PENDING) {
779 item->ClearTransaction();
780 pending_op->callback.Run(rv);
783 return rv;
786 void HttpCache::DoomMainEntryForUrl(const GURL& url) {
787 if (!disk_cache_)
788 return;
790 HttpRequestInfo temp_info;
791 temp_info.url = url;
792 temp_info.method = "GET";
793 std::string key = GenerateCacheKey(&temp_info);
795 // Defer to DoomEntry if there is an active entry, otherwise call
796 // AsyncDoomEntry without triggering a callback.
797 if (active_entries_.count(key))
798 DoomEntry(key, NULL);
799 else
800 AsyncDoomEntry(key, NULL);
803 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) {
804 DCHECK(entry->doomed);
805 DCHECK(!entry->writer);
806 DCHECK(entry->readers.empty());
807 DCHECK(entry->pending_queue.empty());
809 ActiveEntriesSet::iterator it = doomed_entries_.find(entry);
810 DCHECK(it != doomed_entries_.end());
811 doomed_entries_.erase(it);
813 delete entry;
816 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
817 ActiveEntriesMap::const_iterator it = active_entries_.find(key);
818 return it != active_entries_.end() ? it->second : NULL;
821 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
822 disk_cache::Entry* disk_entry) {
823 DCHECK(!FindActiveEntry(disk_entry->GetKey()));
824 ActiveEntry* entry = new ActiveEntry(disk_entry);
825 active_entries_[disk_entry->GetKey()] = entry;
826 return entry;
829 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
830 DCHECK(!entry->will_process_pending_queue);
831 DCHECK(!entry->doomed);
832 DCHECK(!entry->writer);
833 DCHECK(entry->disk_entry);
834 DCHECK(entry->readers.empty());
835 DCHECK(entry->pending_queue.empty());
837 std::string key = entry->disk_entry->GetKey();
838 if (key.empty())
839 return SlowDeactivateEntry(entry);
841 ActiveEntriesMap::iterator it = active_entries_.find(key);
842 DCHECK(it != active_entries_.end());
843 DCHECK(it->second == entry);
845 active_entries_.erase(it);
846 delete entry;
849 // We don't know this entry's key so we have to find it without it.
850 void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) {
851 for (ActiveEntriesMap::iterator it = active_entries_.begin();
852 it != active_entries_.end(); ++it) {
853 if (it->second == entry) {
854 active_entries_.erase(it);
855 delete entry;
856 break;
861 HttpCache::PendingOp* HttpCache::GetPendingOp(const std::string& key) {
862 DCHECK(!FindActiveEntry(key));
864 PendingOpsMap::const_iterator it = pending_ops_.find(key);
865 if (it != pending_ops_.end())
866 return it->second;
868 PendingOp* operation = new PendingOp();
869 pending_ops_[key] = operation;
870 return operation;
873 void HttpCache::DeletePendingOp(PendingOp* pending_op) {
874 std::string key;
875 if (pending_op->disk_entry)
876 key = pending_op->disk_entry->GetKey();
878 if (!key.empty()) {
879 PendingOpsMap::iterator it = pending_ops_.find(key);
880 DCHECK(it != pending_ops_.end());
881 pending_ops_.erase(it);
882 } else {
883 for (PendingOpsMap::iterator it = pending_ops_.begin();
884 it != pending_ops_.end(); ++it) {
885 if (it->second == pending_op) {
886 pending_ops_.erase(it);
887 break;
891 DCHECK(pending_op->pending_queue.empty());
893 delete pending_op;
896 int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry,
897 Transaction* trans) {
898 ActiveEntry* active_entry = FindActiveEntry(key);
899 if (active_entry) {
900 *entry = active_entry;
901 return OK;
904 WorkItem* item = new WorkItem(WI_OPEN_ENTRY, trans, entry);
905 PendingOp* pending_op = GetPendingOp(key);
906 if (pending_op->writer) {
907 pending_op->pending_queue.push_back(item);
908 return ERR_IO_PENDING;
911 DCHECK(pending_op->pending_queue.empty());
913 pending_op->writer = item;
914 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
915 GetWeakPtr(), pending_op);
917 int rv = disk_cache_->OpenEntry(key, &(pending_op->disk_entry),
918 pending_op->callback);
919 if (rv != ERR_IO_PENDING) {
920 item->ClearTransaction();
921 pending_op->callback.Run(rv);
924 return rv;
927 int HttpCache::CreateEntry(const std::string& key, ActiveEntry** entry,
928 Transaction* trans) {
929 if (FindActiveEntry(key)) {
930 return ERR_CACHE_RACE;
933 WorkItem* item = new WorkItem(WI_CREATE_ENTRY, trans, entry);
934 PendingOp* pending_op = GetPendingOp(key);
935 if (pending_op->writer) {
936 pending_op->pending_queue.push_back(item);
937 return ERR_IO_PENDING;
940 DCHECK(pending_op->pending_queue.empty());
942 pending_op->writer = item;
943 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
944 GetWeakPtr(), pending_op);
946 int rv = disk_cache_->CreateEntry(key, &(pending_op->disk_entry),
947 pending_op->callback);
948 if (rv != ERR_IO_PENDING) {
949 item->ClearTransaction();
950 pending_op->callback.Run(rv);
953 return rv;
956 void HttpCache::DestroyEntry(ActiveEntry* entry) {
957 if (entry->doomed) {
958 FinalizeDoomedEntry(entry);
959 } else {
960 DeactivateEntry(entry);
964 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
965 DCHECK(entry);
966 DCHECK(entry->disk_entry);
968 // We implement a basic reader/writer lock for the disk cache entry. If
969 // there is already a writer, then everyone has to wait for the writer to
970 // finish before they can access the cache entry. There can be multiple
971 // readers.
973 // NOTE: If the transaction can only write, then the entry should not be in
974 // use (since any existing entry should have already been doomed).
976 if (entry->writer || entry->will_process_pending_queue) {
977 entry->pending_queue.push_back(trans);
978 return ERR_IO_PENDING;
981 if (trans->mode() & Transaction::WRITE) {
982 // transaction needs exclusive access to the entry
983 if (entry->readers.empty()) {
984 entry->writer = trans;
985 } else {
986 entry->pending_queue.push_back(trans);
987 return ERR_IO_PENDING;
989 } else {
990 // transaction needs read access to the entry
991 entry->readers.push_back(trans);
994 // We do this before calling EntryAvailable to force any further calls to
995 // AddTransactionToEntry to add their transaction to the pending queue, which
996 // ensures FIFO ordering.
997 if (!entry->writer && !entry->pending_queue.empty())
998 ProcessPendingQueue(entry);
1000 return OK;
1003 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
1004 bool cancel) {
1005 // If we already posted a task to move on to the next transaction and this was
1006 // the writer, there is nothing to cancel.
1007 if (entry->will_process_pending_queue && entry->readers.empty())
1008 return;
1010 if (entry->writer) {
1011 DCHECK(trans == entry->writer);
1013 // Assume there was a failure.
1014 bool success = false;
1015 if (cancel) {
1016 DCHECK(entry->disk_entry);
1017 // This is a successful operation in the sense that we want to keep the
1018 // entry.
1019 success = trans->AddTruncatedFlag();
1020 // The previous operation may have deleted the entry.
1021 if (!trans->entry())
1022 return;
1024 DoneWritingToEntry(entry, success);
1025 } else {
1026 DoneReadingFromEntry(entry, trans);
1030 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
1031 DCHECK(entry->readers.empty());
1033 entry->writer = NULL;
1035 if (success) {
1036 ProcessPendingQueue(entry);
1037 } else {
1038 DCHECK(!entry->will_process_pending_queue);
1040 // We failed to create this entry.
1041 TransactionList pending_queue;
1042 pending_queue.swap(entry->pending_queue);
1044 entry->disk_entry->Doom();
1045 DestroyEntry(entry);
1047 // We need to do something about these pending entries, which now need to
1048 // be added to a new entry.
1049 while (!pending_queue.empty()) {
1050 // ERR_CACHE_RACE causes the transaction to restart the whole process.
1051 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE);
1052 pending_queue.pop_front();
1057 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
1058 DCHECK(!entry->writer);
1060 TransactionList::iterator it =
1061 std::find(entry->readers.begin(), entry->readers.end(), trans);
1062 DCHECK(it != entry->readers.end());
1064 entry->readers.erase(it);
1066 ProcessPendingQueue(entry);
1069 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
1070 DCHECK(entry->writer);
1071 DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
1072 DCHECK(entry->readers.empty());
1074 Transaction* trans = entry->writer;
1076 entry->writer = NULL;
1077 entry->readers.push_back(trans);
1079 ProcessPendingQueue(entry);
1082 LoadState HttpCache::GetLoadStateForPendingTransaction(
1083 const Transaction* trans) {
1084 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
1085 if (i == active_entries_.end()) {
1086 // If this is really a pending transaction, and it is not part of
1087 // active_entries_, we should be creating the backend or the entry.
1088 return LOAD_STATE_WAITING_FOR_CACHE;
1091 Transaction* writer = i->second->writer;
1092 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE;
1095 void HttpCache::RemovePendingTransaction(Transaction* trans) {
1096 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
1097 bool found = false;
1098 if (i != active_entries_.end())
1099 found = RemovePendingTransactionFromEntry(i->second, trans);
1101 if (found)
1102 return;
1104 if (building_backend_) {
1105 PendingOpsMap::const_iterator j = pending_ops_.find(std::string());
1106 if (j != pending_ops_.end())
1107 found = RemovePendingTransactionFromPendingOp(j->second, trans);
1109 if (found)
1110 return;
1113 PendingOpsMap::const_iterator j = pending_ops_.find(trans->key());
1114 if (j != pending_ops_.end())
1115 found = RemovePendingTransactionFromPendingOp(j->second, trans);
1117 if (found)
1118 return;
1120 ActiveEntriesSet::iterator k = doomed_entries_.begin();
1121 for (; k != doomed_entries_.end() && !found; ++k)
1122 found = RemovePendingTransactionFromEntry(*k, trans);
1124 DCHECK(found) << "Pending transaction not found";
1127 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
1128 Transaction* trans) {
1129 TransactionList& pending_queue = entry->pending_queue;
1131 TransactionList::iterator j =
1132 find(pending_queue.begin(), pending_queue.end(), trans);
1133 if (j == pending_queue.end())
1134 return false;
1136 pending_queue.erase(j);
1137 return true;
1140 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
1141 Transaction* trans) {
1142 if (pending_op->writer->Matches(trans)) {
1143 pending_op->writer->ClearTransaction();
1144 pending_op->writer->ClearEntry();
1145 return true;
1147 WorkItemList& pending_queue = pending_op->pending_queue;
1149 WorkItemList::iterator it = pending_queue.begin();
1150 for (; it != pending_queue.end(); ++it) {
1151 if ((*it)->Matches(trans)) {
1152 delete *it;
1153 pending_queue.erase(it);
1154 return true;
1157 return false;
1160 void HttpCache::SetupQuicServerInfoFactory(HttpNetworkSession* session) {
1161 if (session &&
1162 !session->quic_stream_factory()->has_quic_server_info_factory()) {
1163 DCHECK(!quic_server_info_factory_);
1164 quic_server_info_factory_.reset(new QuicServerInfoFactoryAdaptor(this));
1165 session->quic_stream_factory()->set_quic_server_info_factory(
1166 quic_server_info_factory_.get());
1170 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
1171 // Multiple readers may finish with an entry at once, so we want to batch up
1172 // calls to OnProcessPendingQueue. This flag also tells us that we should
1173 // not delete the entry before OnProcessPendingQueue runs.
1174 if (entry->will_process_pending_queue)
1175 return;
1176 entry->will_process_pending_queue = true;
1178 base::MessageLoop::current()->PostTask(
1179 FROM_HERE,
1180 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
1183 void HttpCache::PerformAsyncValidation(const HttpRequestInfo& original_request,
1184 const BoundNetLog& net_log) {
1185 DCHECK(use_stale_while_revalidate_);
1186 std::string key = GenerateCacheKey(&original_request);
1187 AsyncValidation* async_validation =
1188 new AsyncValidation(original_request, this);
1189 typedef AsyncValidationMap::value_type AsyncValidationKeyValue;
1190 bool insert_ok =
1191 async_validations_.insert(AsyncValidationKeyValue(key, async_validation))
1192 .second;
1193 if (!insert_ok) {
1194 DVLOG(1) << "Harmless race condition detected on URL "
1195 << original_request.url << "; discarding redundant revalidation.";
1196 delete async_validation;
1197 return;
1199 HttpNetworkSession* network_session = GetSession();
1200 NetworkDelegate* network_delegate = NULL;
1201 if (network_session)
1202 network_delegate = network_session->network_delegate();
1203 scoped_ptr<HttpTransaction> transaction;
1204 CreateTransaction(IDLE, &transaction);
1205 scoped_ptr<Transaction> downcast_transaction(
1206 static_cast<Transaction*>(transaction.release()));
1207 async_validation->Start(
1208 net_log, downcast_transaction.Pass(), network_delegate);
1209 // |async_validation| may have been deleted here.
1212 void HttpCache::DeleteAsyncValidation(const std::string& url) {
1213 AsyncValidationMap::iterator it = async_validations_.find(url);
1214 CHECK(it != async_validations_.end()); // security-critical invariant
1215 AsyncValidation* async_validation = it->second;
1216 async_validations_.erase(it);
1217 delete async_validation;
1220 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
1221 entry->will_process_pending_queue = false;
1222 DCHECK(!entry->writer);
1224 // If no one is interested in this entry, then we can deactivate it.
1225 if (entry->pending_queue.empty()) {
1226 if (entry->readers.empty())
1227 DestroyEntry(entry);
1228 return;
1231 // Promote next transaction from the pending queue.
1232 Transaction* next = entry->pending_queue.front();
1233 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
1234 return; // Have to wait.
1236 entry->pending_queue.erase(entry->pending_queue.begin());
1238 int rv = AddTransactionToEntry(entry, next);
1239 if (rv != ERR_IO_PENDING) {
1240 next->io_callback().Run(rv);
1244 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
1245 WorkItemOperation op = pending_op->writer->operation();
1247 // Completing the creation of the backend is simpler than the other cases.
1248 if (op == WI_CREATE_BACKEND)
1249 return OnBackendCreated(result, pending_op);
1251 scoped_ptr<WorkItem> item(pending_op->writer);
1252 bool fail_requests = false;
1254 ActiveEntry* entry = NULL;
1255 std::string key;
1256 if (result == OK) {
1257 if (op == WI_DOOM_ENTRY) {
1258 // Anything after a Doom has to be restarted.
1259 fail_requests = true;
1260 } else if (item->IsValid()) {
1261 key = pending_op->disk_entry->GetKey();
1262 entry = ActivateEntry(pending_op->disk_entry);
1263 } else {
1264 // The writer transaction is gone.
1265 if (op == WI_CREATE_ENTRY)
1266 pending_op->disk_entry->Doom();
1267 pending_op->disk_entry->Close();
1268 pending_op->disk_entry = NULL;
1269 fail_requests = true;
1273 // We are about to notify a bunch of transactions, and they may decide to
1274 // re-issue a request (or send a different one). If we don't delete
1275 // pending_op, the new request will be appended to the end of the list, and
1276 // we'll see it again from this point before it has a chance to complete (and
1277 // we'll be messing out the request order). The down side is that if for some
1278 // reason notifying request A ends up cancelling request B (for the same key),
1279 // we won't find request B anywhere (because it would be in a local variable
1280 // here) and that's bad. If there is a chance for that to happen, we'll have
1281 // to move the callback used to be a CancelableCallback. By the way, for this
1282 // to happen the action (to cancel B) has to be synchronous to the
1283 // notification for request A.
1284 WorkItemList pending_items;
1285 pending_items.swap(pending_op->pending_queue);
1286 DeletePendingOp(pending_op);
1288 item->NotifyTransaction(result, entry);
1290 while (!pending_items.empty()) {
1291 item.reset(pending_items.front());
1292 pending_items.pop_front();
1294 if (item->operation() == WI_DOOM_ENTRY) {
1295 // A queued doom request is always a race.
1296 fail_requests = true;
1297 } else if (result == OK) {
1298 entry = FindActiveEntry(key);
1299 if (!entry)
1300 fail_requests = true;
1303 if (fail_requests) {
1304 item->NotifyTransaction(ERR_CACHE_RACE, NULL);
1305 continue;
1308 if (item->operation() == WI_CREATE_ENTRY) {
1309 if (result == OK) {
1310 // A second Create request, but the first request succeeded.
1311 item->NotifyTransaction(ERR_CACHE_CREATE_FAILURE, NULL);
1312 } else {
1313 if (op != WI_CREATE_ENTRY) {
1314 // Failed Open followed by a Create.
1315 item->NotifyTransaction(ERR_CACHE_RACE, NULL);
1316 fail_requests = true;
1317 } else {
1318 item->NotifyTransaction(result, entry);
1321 } else {
1322 if (op == WI_CREATE_ENTRY && result != OK) {
1323 // Failed Create followed by an Open.
1324 item->NotifyTransaction(ERR_CACHE_RACE, NULL);
1325 fail_requests = true;
1326 } else {
1327 item->NotifyTransaction(result, entry);
1333 // static
1334 void HttpCache::OnPendingOpComplete(const base::WeakPtr<HttpCache>& cache,
1335 PendingOp* pending_op,
1336 int rv) {
1337 if (cache.get()) {
1338 cache->OnIOComplete(rv, pending_op);
1339 } else {
1340 // The callback was cancelled so we should delete the pending_op that
1341 // was used with this callback.
1342 delete pending_op;
1346 void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) {
1347 scoped_ptr<WorkItem> item(pending_op->writer);
1348 WorkItemOperation op = item->operation();
1349 DCHECK_EQ(WI_CREATE_BACKEND, op);
1351 // We don't need the callback anymore.
1352 pending_op->callback.Reset();
1354 if (backend_factory_.get()) {
1355 // We may end up calling OnBackendCreated multiple times if we have pending
1356 // work items. The first call saves the backend and releases the factory,
1357 // and the last call clears building_backend_.
1358 backend_factory_.reset(); // Reclaim memory.
1359 if (result == OK) {
1360 disk_cache_ = pending_op->backend.Pass();
1361 if (UseCertCache())
1362 cert_cache_.reset(new DiskBasedCertCache(disk_cache_.get()));
1366 if (!pending_op->pending_queue.empty()) {
1367 WorkItem* pending_item = pending_op->pending_queue.front();
1368 pending_op->pending_queue.pop_front();
1369 DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation());
1371 // We want to process a single callback at a time, because the cache may
1372 // go away from the callback.
1373 pending_op->writer = pending_item;
1375 base::MessageLoop::current()->PostTask(
1376 FROM_HERE,
1377 base::Bind(&HttpCache::OnBackendCreated, GetWeakPtr(),
1378 result, pending_op));
1379 } else {
1380 building_backend_ = false;
1381 DeletePendingOp(pending_op);
1384 // The cache may be gone when we return from the callback.
1385 if (!item->DoCallback(result, disk_cache_.get()))
1386 item->NotifyTransaction(result, NULL);
1389 } // namespace net