Home | History | Annotate | Download | only in http
      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.
      4 
      5 #include "net/http/http_cache.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/compiler_specific.h"
     10 
     11 #if defined(OS_POSIX)
     12 #include <unistd.h>
     13 #endif
     14 
     15 #include "base/bind.h"
     16 #include "base/bind_helpers.h"
     17 #include "base/callback.h"
     18 #include "base/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/pickle.h"
     25 #include "base/stl_util.h"
     26 #include "base/strings/string_number_conversions.h"
     27 #include "base/strings/string_util.h"
     28 #include "base/strings/stringprintf.h"
     29 #include "base/threading/worker_pool.h"
     30 #include "net/base/cache_type.h"
     31 #include "net/base/io_buffer.h"
     32 #include "net/base/load_flags.h"
     33 #include "net/base/net_errors.h"
     34 #include "net/base/upload_data_stream.h"
     35 #include "net/disk_cache/disk_cache.h"
     36 #include "net/http/http_cache_transaction.h"
     37 #include "net/http/http_network_layer.h"
     38 #include "net/http/http_network_session.h"
     39 #include "net/http/http_request_info.h"
     40 #include "net/http/http_response_headers.h"
     41 #include "net/http/http_response_info.h"
     42 #include "net/http/http_util.h"
     43 
     44 namespace {
     45 
     46 // Adaptor to delete a file on a worker thread.
     47 void DeletePath(base::FilePath path) {
     48   base::DeleteFile(path, false);
     49 }
     50 
     51 }  // namespace
     52 
     53 namespace net {
     54 
     55 HttpCache::DefaultBackend::DefaultBackend(CacheType type,
     56                                           BackendType backend_type,
     57                                           const base::FilePath& path,
     58                                           int max_bytes,
     59                                           base::MessageLoopProxy* thread)
     60     : type_(type),
     61       backend_type_(backend_type),
     62       path_(path),
     63       max_bytes_(max_bytes),
     64       thread_(thread) {
     65 }
     66 
     67 HttpCache::DefaultBackend::~DefaultBackend() {}
     68 
     69 // static
     70 HttpCache::BackendFactory* HttpCache::DefaultBackend::InMemory(int max_bytes) {
     71   return new DefaultBackend(MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT,
     72                             base::FilePath(), max_bytes, NULL);
     73 }
     74 
     75 int HttpCache::DefaultBackend::CreateBackend(
     76     NetLog* net_log, scoped_ptr<disk_cache::Backend>* backend,
     77     const CompletionCallback& callback) {
     78   DCHECK_GE(max_bytes_, 0);
     79   return disk_cache::CreateCacheBackend(type_,
     80                                         backend_type_,
     81                                         path_,
     82                                         max_bytes_,
     83                                         true,
     84                                         thread_.get(),
     85                                         net_log,
     86                                         backend,
     87                                         callback);
     88 }
     89 
     90 //-----------------------------------------------------------------------------
     91 
     92 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
     93     : disk_entry(entry),
     94       writer(NULL),
     95       will_process_pending_queue(false),
     96       doomed(false) {
     97 }
     98 
     99 HttpCache::ActiveEntry::~ActiveEntry() {
    100   if (disk_entry) {
    101     disk_entry->Close();
    102     disk_entry = NULL;
    103   }
    104 }
    105 
    106 //-----------------------------------------------------------------------------
    107 
    108 // This structure keeps track of work items that are attempting to create or
    109 // open cache entries or the backend itself.
    110 struct HttpCache::PendingOp {
    111   PendingOp() : disk_entry(NULL), writer(NULL) {}
    112   ~PendingOp() {}
    113 
    114   disk_cache::Entry* disk_entry;
    115   scoped_ptr<disk_cache::Backend> backend;
    116   WorkItem* writer;
    117   CompletionCallback callback;  // BackendCallback.
    118   WorkItemList pending_queue;
    119 };
    120 
    121 //-----------------------------------------------------------------------------
    122 
    123 // The type of operation represented by a work item.
    124 enum WorkItemOperation {
    125   WI_CREATE_BACKEND,
    126   WI_OPEN_ENTRY,
    127   WI_CREATE_ENTRY,
    128   WI_DOOM_ENTRY
    129 };
    130 
    131 // A work item encapsulates a single request to the backend with all the
    132 // information needed to complete that request.
    133 class HttpCache::WorkItem {
    134  public:
    135   WorkItem(WorkItemOperation operation, Transaction* trans, ActiveEntry** entry)
    136       : operation_(operation),
    137         trans_(trans),
    138         entry_(entry),
    139         backend_(NULL) {}
    140   WorkItem(WorkItemOperation operation, Transaction* trans,
    141            const net::CompletionCallback& cb, disk_cache::Backend** backend)
    142       : operation_(operation),
    143         trans_(trans),
    144         entry_(NULL),
    145         callback_(cb),
    146         backend_(backend) {}
    147   ~WorkItem() {}
    148 
    149   // Calls back the transaction with the result of the operation.
    150   void NotifyTransaction(int result, ActiveEntry* entry) {
    151     DCHECK(!entry || entry->disk_entry);
    152     if (entry_)
    153       *entry_ = entry;
    154     if (trans_)
    155       trans_->io_callback().Run(result);
    156   }
    157 
    158   // Notifies the caller about the operation completion. Returns true if the
    159   // callback was invoked.
    160   bool DoCallback(int result, disk_cache::Backend* backend) {
    161     if (backend_)
    162       *backend_ = backend;
    163     if (!callback_.is_null()) {
    164       callback_.Run(result);
    165       return true;
    166     }
    167     return false;
    168   }
    169 
    170   WorkItemOperation operation() { return operation_; }
    171   void ClearTransaction() { trans_ = NULL; }
    172   void ClearEntry() { entry_ = NULL; }
    173   void ClearCallback() { callback_.Reset(); }
    174   bool Matches(Transaction* trans) const { return trans == trans_; }
    175   bool IsValid() const { return trans_ || entry_ || !callback_.is_null(); }
    176 
    177  private:
    178   WorkItemOperation operation_;
    179   Transaction* trans_;
    180   ActiveEntry** entry_;
    181   net::CompletionCallback callback_;  // User callback.
    182   disk_cache::Backend** backend_;
    183 };
    184 
    185 //-----------------------------------------------------------------------------
    186 
    187 // This class encapsulates a transaction whose only purpose is to write metadata
    188 // to a given entry.
    189 class HttpCache::MetadataWriter {
    190  public:
    191   explicit MetadataWriter(HttpCache::Transaction* trans)
    192       : transaction_(trans),
    193         verified_(false),
    194         buf_len_(0) {
    195   }
    196 
    197   ~MetadataWriter() {}
    198 
    199   // Implements the bulk of HttpCache::WriteMetadata.
    200   void Write(const GURL& url, base::Time expected_response_time, IOBuffer* buf,
    201              int buf_len);
    202 
    203  private:
    204   void VerifyResponse(int result);
    205   void SelfDestroy();
    206   void OnIOComplete(int result);
    207 
    208   scoped_ptr<HttpCache::Transaction> transaction_;
    209   bool verified_;
    210   scoped_refptr<IOBuffer> buf_;
    211   int buf_len_;
    212   base::Time expected_response_time_;
    213   HttpRequestInfo request_info_;
    214   DISALLOW_COPY_AND_ASSIGN(MetadataWriter);
    215 };
    216 
    217 void HttpCache::MetadataWriter::Write(const GURL& url,
    218                                       base::Time expected_response_time,
    219                                       IOBuffer* buf, int buf_len) {
    220   DCHECK_GT(buf_len, 0);
    221   DCHECK(buf);
    222   DCHECK(buf->data());
    223   request_info_.url = url;
    224   request_info_.method = "GET";
    225   request_info_.load_flags = LOAD_ONLY_FROM_CACHE;
    226 
    227   expected_response_time_ = expected_response_time;
    228   buf_ = buf;
    229   buf_len_ = buf_len;
    230   verified_ = false;
    231 
    232   int rv = transaction_->Start(
    233       &request_info_,
    234       base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this)),
    235       BoundNetLog());
    236   if (rv != ERR_IO_PENDING)
    237     VerifyResponse(rv);
    238 }
    239 
    240 void HttpCache::MetadataWriter::VerifyResponse(int result) {
    241   verified_ = true;
    242   if (result != OK)
    243     return SelfDestroy();
    244 
    245   const HttpResponseInfo* response_info = transaction_->GetResponseInfo();
    246   DCHECK(response_info->was_cached);
    247   if (response_info->response_time != expected_response_time_)
    248     return SelfDestroy();
    249 
    250   result = transaction_->WriteMetadata(
    251       buf_.get(),
    252       buf_len_,
    253       base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this)));
    254   if (result != ERR_IO_PENDING)
    255     SelfDestroy();
    256 }
    257 
    258 void HttpCache::MetadataWriter::SelfDestroy() {
    259   delete this;
    260 }
    261 
    262 void HttpCache::MetadataWriter::OnIOComplete(int result) {
    263   if (!verified_)
    264     return VerifyResponse(result);
    265   SelfDestroy();
    266 }
    267 
    268 //-----------------------------------------------------------------------------
    269 
    270 HttpCache::HttpCache(const net::HttpNetworkSession::Params& params,
    271                      BackendFactory* backend_factory)
    272     : net_log_(params.net_log),
    273       backend_factory_(backend_factory),
    274       building_backend_(false),
    275       mode_(NORMAL),
    276       network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))) {
    277 }
    278 
    279 
    280 HttpCache::HttpCache(HttpNetworkSession* session,
    281                      BackendFactory* backend_factory)
    282     : net_log_(session->net_log()),
    283       backend_factory_(backend_factory),
    284       building_backend_(false),
    285       mode_(NORMAL),
    286       network_layer_(new HttpNetworkLayer(session)) {
    287 }
    288 
    289 HttpCache::HttpCache(HttpTransactionFactory* network_layer,
    290                      NetLog* net_log,
    291                      BackendFactory* backend_factory)
    292     : net_log_(net_log),
    293       backend_factory_(backend_factory),
    294       building_backend_(false),
    295       mode_(NORMAL),
    296       network_layer_(network_layer) {
    297 }
    298 
    299 HttpCache::~HttpCache() {
    300   // If we have any active entries remaining, then we need to deactivate them.
    301   // We may have some pending calls to OnProcessPendingQueue, but since those
    302   // won't run (due to our destruction), we can simply ignore the corresponding
    303   // will_process_pending_queue flag.
    304   while (!active_entries_.empty()) {
    305     ActiveEntry* entry = active_entries_.begin()->second;
    306     entry->will_process_pending_queue = false;
    307     entry->pending_queue.clear();
    308     entry->readers.clear();
    309     entry->writer = NULL;
    310     DeactivateEntry(entry);
    311   }
    312 
    313   STLDeleteElements(&doomed_entries_);
    314 
    315   // Before deleting pending_ops_, we have to make sure that the disk cache is
    316   // done with said operations, or it will attempt to use deleted data.
    317   disk_cache_.reset();
    318 
    319   PendingOpsMap::iterator pending_it = pending_ops_.begin();
    320   for (; pending_it != pending_ops_.end(); ++pending_it) {
    321     // We are not notifying the transactions about the cache going away, even
    322     // though they are waiting for a callback that will never fire.
    323     PendingOp* pending_op = pending_it->second;
    324     delete pending_op->writer;
    325     bool delete_pending_op = true;
    326     if (building_backend_) {
    327       // If we don't have a backend, when its construction finishes it will
    328       // deliver the callbacks.
    329       if (!pending_op->callback.is_null()) {
    330         // If not null, the callback will delete the pending operation later.
    331         delete_pending_op = false;
    332       }
    333     } else {
    334       pending_op->callback.Reset();
    335     }
    336 
    337     STLDeleteElements(&pending_op->pending_queue);
    338     if (delete_pending_op)
    339       delete pending_op;
    340   }
    341 }
    342 
    343 int HttpCache::GetBackend(disk_cache::Backend** backend,
    344                           const CompletionCallback& callback) {
    345   DCHECK(!callback.is_null());
    346 
    347   if (disk_cache_.get()) {
    348     *backend = disk_cache_.get();
    349     return OK;
    350   }
    351 
    352   return CreateBackend(backend, callback);
    353 }
    354 
    355 disk_cache::Backend* HttpCache::GetCurrentBackend() const {
    356   return disk_cache_.get();
    357 }
    358 
    359 // static
    360 bool HttpCache::ParseResponseInfo(const char* data, int len,
    361                                   HttpResponseInfo* response_info,
    362                                   bool* response_truncated) {
    363   Pickle pickle(data, len);
    364   return response_info->InitFromPickle(pickle, response_truncated);
    365 }
    366 
    367 void HttpCache::WriteMetadata(const GURL& url,
    368                               RequestPriority priority,
    369                               base::Time expected_response_time,
    370                               IOBuffer* buf,
    371                               int buf_len) {
    372   if (!buf_len)
    373     return;
    374 
    375   // Do lazy initialization of disk cache if needed.
    376   if (!disk_cache_.get()) {
    377     // We don't care about the result.
    378     CreateBackend(NULL, net::CompletionCallback());
    379   }
    380 
    381   HttpCache::Transaction* trans =
    382       new HttpCache::Transaction(priority, this, NULL);
    383   MetadataWriter* writer = new MetadataWriter(trans);
    384 
    385   // The writer will self destruct when done.
    386   writer->Write(url, expected_response_time, buf, buf_len);
    387 }
    388 
    389 void HttpCache::CloseAllConnections() {
    390   net::HttpNetworkLayer* network =
    391       static_cast<net::HttpNetworkLayer*>(network_layer_.get());
    392   HttpNetworkSession* session = network->GetSession();
    393   if (session)
    394     session->CloseAllConnections();
    395 }
    396 
    397 void HttpCache::CloseIdleConnections() {
    398   net::HttpNetworkLayer* network =
    399       static_cast<net::HttpNetworkLayer*>(network_layer_.get());
    400   HttpNetworkSession* session = network->GetSession();
    401   if (session)
    402     session->CloseIdleConnections();
    403 }
    404 
    405 void HttpCache::OnExternalCacheHit(const GURL& url,
    406                                    const std::string& http_method) {
    407   if (!disk_cache_.get())
    408     return;
    409 
    410   HttpRequestInfo request_info;
    411   request_info.url = url;
    412   request_info.method = http_method;
    413   std::string key = GenerateCacheKey(&request_info);
    414   disk_cache_->OnExternalCacheHit(key);
    415 }
    416 
    417 void HttpCache::InitializeInfiniteCache(const base::FilePath& path) {
    418   if (base::FieldTrialList::FindFullName("InfiniteCache") != "Yes")
    419     return;
    420   base::WorkerPool::PostTask(FROM_HERE, base::Bind(&DeletePath, path), true);
    421 }
    422 
    423 int HttpCache::CreateTransaction(RequestPriority priority,
    424                                  scoped_ptr<HttpTransaction>* trans,
    425                                  HttpTransactionDelegate* delegate) {
    426   // Do lazy initialization of disk cache if needed.
    427   if (!disk_cache_.get()) {
    428     // We don't care about the result.
    429     CreateBackend(NULL, net::CompletionCallback());
    430   }
    431 
    432   trans->reset(new HttpCache::Transaction(priority, this, delegate));
    433   return OK;
    434 }
    435 
    436 HttpCache* HttpCache::GetCache() {
    437   return this;
    438 }
    439 
    440 HttpNetworkSession* HttpCache::GetSession() {
    441   net::HttpNetworkLayer* network =
    442       static_cast<net::HttpNetworkLayer*>(network_layer_.get());
    443   return network->GetSession();
    444 }
    445 
    446 //-----------------------------------------------------------------------------
    447 
    448 int HttpCache::CreateBackend(disk_cache::Backend** backend,
    449                              const net::CompletionCallback& callback) {
    450   if (!backend_factory_.get())
    451     return ERR_FAILED;
    452 
    453   building_backend_ = true;
    454 
    455   scoped_ptr<WorkItem> item(new WorkItem(WI_CREATE_BACKEND, NULL, callback,
    456                                          backend));
    457 
    458   // This is the only operation that we can do that is not related to any given
    459   // entry, so we use an empty key for it.
    460   PendingOp* pending_op = GetPendingOp(std::string());
    461   if (pending_op->writer) {
    462     if (!callback.is_null())
    463       pending_op->pending_queue.push_back(item.release());
    464     return ERR_IO_PENDING;
    465   }
    466 
    467   DCHECK(pending_op->pending_queue.empty());
    468 
    469   pending_op->writer = item.release();
    470   pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
    471                                     AsWeakPtr(), pending_op);
    472 
    473   int rv = backend_factory_->CreateBackend(net_log_, &pending_op->backend,
    474                                            pending_op->callback);
    475   if (rv != ERR_IO_PENDING) {
    476     pending_op->writer->ClearCallback();
    477     pending_op->callback.Run(rv);
    478   }
    479 
    480   return rv;
    481 }
    482 
    483 int HttpCache::GetBackendForTransaction(Transaction* trans) {
    484   if (disk_cache_.get())
    485     return OK;
    486 
    487   if (!building_backend_)
    488     return ERR_FAILED;
    489 
    490   WorkItem* item = new WorkItem(
    491       WI_CREATE_BACKEND, trans, net::CompletionCallback(), NULL);
    492   PendingOp* pending_op = GetPendingOp(std::string());
    493   DCHECK(pending_op->writer);
    494   pending_op->pending_queue.push_back(item);
    495   return ERR_IO_PENDING;
    496 }
    497 
    498 // Generate a key that can be used inside the cache.
    499 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
    500   // Strip out the reference, username, and password sections of the URL.
    501   std::string url = HttpUtil::SpecForRequest(request->url);
    502 
    503   DCHECK(mode_ != DISABLE);
    504   if (mode_ == NORMAL) {
    505     // No valid URL can begin with numerals, so we should not have to worry
    506     // about collisions with normal URLs.
    507     if (request->upload_data_stream &&
    508         request->upload_data_stream->identifier()) {
    509       url.insert(0, base::StringPrintf(
    510           "%" PRId64 "/", request->upload_data_stream->identifier()));
    511     }
    512     return url;
    513   }
    514 
    515   // In playback and record mode, we cache everything.
    516 
    517   // Lazily initialize.
    518   if (playback_cache_map_ == NULL)
    519     playback_cache_map_.reset(new PlaybackCacheMap());
    520 
    521   // Each time we request an item from the cache, we tag it with a
    522   // generation number.  During playback, multiple fetches for the same
    523   // item will use the same generation number and pull the proper
    524   // instance of an URL from the cache.
    525   int generation = 0;
    526   DCHECK(playback_cache_map_ != NULL);
    527   if (playback_cache_map_->find(url) != playback_cache_map_->end())
    528     generation = (*playback_cache_map_)[url];
    529   (*playback_cache_map_)[url] = generation + 1;
    530 
    531   // The key into the cache is GENERATION # + METHOD + URL.
    532   std::string result = base::IntToString(generation);
    533   result.append(request->method);
    534   result.append(url);
    535   return result;
    536 }
    537 
    538 void HttpCache::DoomActiveEntry(const std::string& key) {
    539   ActiveEntriesMap::iterator it = active_entries_.find(key);
    540   if (it == active_entries_.end())
    541     return;
    542 
    543   // This is not a performance critical operation, this is handling an error
    544   // condition so it is OK to look up the entry again.
    545   int rv = DoomEntry(key, NULL);
    546   DCHECK_EQ(OK, rv);
    547 }
    548 
    549 int HttpCache::DoomEntry(const std::string& key, Transaction* trans) {
    550   // Need to abandon the ActiveEntry, but any transaction attached to the entry
    551   // should not be impacted.  Dooming an entry only means that it will no
    552   // longer be returned by FindActiveEntry (and it will also be destroyed once
    553   // all consumers are finished with the entry).
    554   ActiveEntriesMap::iterator it = active_entries_.find(key);
    555   if (it == active_entries_.end()) {
    556     DCHECK(trans);
    557     return AsyncDoomEntry(key, trans);
    558   }
    559 
    560   ActiveEntry* entry = it->second;
    561   active_entries_.erase(it);
    562 
    563   // We keep track of doomed entries so that we can ensure that they are
    564   // cleaned up properly when the cache is destroyed.
    565   doomed_entries_.insert(entry);
    566 
    567   entry->disk_entry->Doom();
    568   entry->doomed = true;
    569 
    570   DCHECK(entry->writer || !entry->readers.empty());
    571   return OK;
    572 }
    573 
    574 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) {
    575   WorkItem* item = new WorkItem(WI_DOOM_ENTRY, trans, NULL);
    576   PendingOp* pending_op = GetPendingOp(key);
    577   if (pending_op->writer) {
    578     pending_op->pending_queue.push_back(item);
    579     return ERR_IO_PENDING;
    580   }
    581 
    582   DCHECK(pending_op->pending_queue.empty());
    583 
    584   pending_op->writer = item;
    585   pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
    586                                     AsWeakPtr(), pending_op);
    587 
    588   int rv = disk_cache_->DoomEntry(key, pending_op->callback);
    589   if (rv != ERR_IO_PENDING) {
    590     item->ClearTransaction();
    591     pending_op->callback.Run(rv);
    592   }
    593 
    594   return rv;
    595 }
    596 
    597 void HttpCache::DoomMainEntryForUrl(const GURL& url) {
    598   if (!disk_cache_)
    599     return;
    600 
    601   HttpRequestInfo temp_info;
    602   temp_info.url = url;
    603   temp_info.method = "GET";
    604   std::string key = GenerateCacheKey(&temp_info);
    605 
    606   // Defer to DoomEntry if there is an active entry, otherwise call
    607   // AsyncDoomEntry without triggering a callback.
    608   if (active_entries_.count(key))
    609     DoomEntry(key, NULL);
    610   else
    611     AsyncDoomEntry(key, NULL);
    612 }
    613 
    614 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) {
    615   DCHECK(entry->doomed);
    616   DCHECK(!entry->writer);
    617   DCHECK(entry->readers.empty());
    618   DCHECK(entry->pending_queue.empty());
    619 
    620   ActiveEntriesSet::iterator it = doomed_entries_.find(entry);
    621   DCHECK(it != doomed_entries_.end());
    622   doomed_entries_.erase(it);
    623 
    624   delete entry;
    625 }
    626 
    627 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
    628   ActiveEntriesMap::const_iterator it = active_entries_.find(key);
    629   return it != active_entries_.end() ? it->second : NULL;
    630 }
    631 
    632 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
    633     disk_cache::Entry* disk_entry) {
    634   DCHECK(!FindActiveEntry(disk_entry->GetKey()));
    635   ActiveEntry* entry = new ActiveEntry(disk_entry);
    636   active_entries_[disk_entry->GetKey()] = entry;
    637   return entry;
    638 }
    639 
    640 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
    641   DCHECK(!entry->will_process_pending_queue);
    642   DCHECK(!entry->doomed);
    643   DCHECK(!entry->writer);
    644   DCHECK(entry->disk_entry);
    645   DCHECK(entry->readers.empty());
    646   DCHECK(entry->pending_queue.empty());
    647 
    648   std::string key = entry->disk_entry->GetKey();
    649   if (key.empty())
    650     return SlowDeactivateEntry(entry);
    651 
    652   ActiveEntriesMap::iterator it = active_entries_.find(key);
    653   DCHECK(it != active_entries_.end());
    654   DCHECK(it->second == entry);
    655 
    656   active_entries_.erase(it);
    657   delete entry;
    658 }
    659 
    660 // We don't know this entry's key so we have to find it without it.
    661 void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) {
    662   for (ActiveEntriesMap::iterator it = active_entries_.begin();
    663        it != active_entries_.end(); ++it) {
    664     if (it->second == entry) {
    665       active_entries_.erase(it);
    666       delete entry;
    667       break;
    668     }
    669   }
    670 }
    671 
    672 HttpCache::PendingOp* HttpCache::GetPendingOp(const std::string& key) {
    673   DCHECK(!FindActiveEntry(key));
    674 
    675   PendingOpsMap::const_iterator it = pending_ops_.find(key);
    676   if (it != pending_ops_.end())
    677     return it->second;
    678 
    679   PendingOp* operation = new PendingOp();
    680   pending_ops_[key] = operation;
    681   return operation;
    682 }
    683 
    684 void HttpCache::DeletePendingOp(PendingOp* pending_op) {
    685   std::string key;
    686   if (pending_op->disk_entry)
    687     key = pending_op->disk_entry->GetKey();
    688 
    689   if (!key.empty()) {
    690     PendingOpsMap::iterator it = pending_ops_.find(key);
    691     DCHECK(it != pending_ops_.end());
    692     pending_ops_.erase(it);
    693   } else {
    694     for (PendingOpsMap::iterator it = pending_ops_.begin();
    695          it != pending_ops_.end(); ++it) {
    696       if (it->second == pending_op) {
    697         pending_ops_.erase(it);
    698         break;
    699       }
    700     }
    701   }
    702   DCHECK(pending_op->pending_queue.empty());
    703 
    704   delete pending_op;
    705 }
    706 
    707 int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry,
    708                          Transaction* trans) {
    709   ActiveEntry* active_entry = FindActiveEntry(key);
    710   if (active_entry) {
    711     *entry = active_entry;
    712     return OK;
    713   }
    714 
    715   WorkItem* item = new WorkItem(WI_OPEN_ENTRY, trans, entry);
    716   PendingOp* pending_op = GetPendingOp(key);
    717   if (pending_op->writer) {
    718     pending_op->pending_queue.push_back(item);
    719     return ERR_IO_PENDING;
    720   }
    721 
    722   DCHECK(pending_op->pending_queue.empty());
    723 
    724   pending_op->writer = item;
    725   pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
    726                                     AsWeakPtr(), pending_op);
    727 
    728   int rv = disk_cache_->OpenEntry(key, &(pending_op->disk_entry),
    729                                   pending_op->callback);
    730   if (rv != ERR_IO_PENDING) {
    731     item->ClearTransaction();
    732     pending_op->callback.Run(rv);
    733   }
    734 
    735   return rv;
    736 }
    737 
    738 int HttpCache::CreateEntry(const std::string& key, ActiveEntry** entry,
    739                            Transaction* trans) {
    740   if (FindActiveEntry(key)) {
    741     return ERR_CACHE_RACE;
    742   }
    743 
    744   WorkItem* item = new WorkItem(WI_CREATE_ENTRY, trans, entry);
    745   PendingOp* pending_op = GetPendingOp(key);
    746   if (pending_op->writer) {
    747     pending_op->pending_queue.push_back(item);
    748     return ERR_IO_PENDING;
    749   }
    750 
    751   DCHECK(pending_op->pending_queue.empty());
    752 
    753   pending_op->writer = item;
    754   pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete,
    755                                     AsWeakPtr(), pending_op);
    756 
    757   int rv = disk_cache_->CreateEntry(key, &(pending_op->disk_entry),
    758                                     pending_op->callback);
    759   if (rv != ERR_IO_PENDING) {
    760     item->ClearTransaction();
    761     pending_op->callback.Run(rv);
    762   }
    763 
    764   return rv;
    765 }
    766 
    767 void HttpCache::DestroyEntry(ActiveEntry* entry) {
    768   if (entry->doomed) {
    769     FinalizeDoomedEntry(entry);
    770   } else {
    771     DeactivateEntry(entry);
    772   }
    773 }
    774 
    775 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
    776   DCHECK(entry);
    777   DCHECK(entry->disk_entry);
    778 
    779   // We implement a basic reader/writer lock for the disk cache entry.  If
    780   // there is already a writer, then everyone has to wait for the writer to
    781   // finish before they can access the cache entry.  There can be multiple
    782   // readers.
    783   //
    784   // NOTE: If the transaction can only write, then the entry should not be in
    785   // use (since any existing entry should have already been doomed).
    786 
    787   if (entry->writer || entry->will_process_pending_queue) {
    788     entry->pending_queue.push_back(trans);
    789     return ERR_IO_PENDING;
    790   }
    791 
    792   if (trans->mode() & Transaction::WRITE) {
    793     // transaction needs exclusive access to the entry
    794     if (entry->readers.empty()) {
    795       entry->writer = trans;
    796     } else {
    797       entry->pending_queue.push_back(trans);
    798       return ERR_IO_PENDING;
    799     }
    800   } else {
    801     // transaction needs read access to the entry
    802     entry->readers.push_back(trans);
    803   }
    804 
    805   // We do this before calling EntryAvailable to force any further calls to
    806   // AddTransactionToEntry to add their transaction to the pending queue, which
    807   // ensures FIFO ordering.
    808   if (!entry->writer && !entry->pending_queue.empty())
    809     ProcessPendingQueue(entry);
    810 
    811   return OK;
    812 }
    813 
    814 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
    815                               bool cancel) {
    816   // If we already posted a task to move on to the next transaction and this was
    817   // the writer, there is nothing to cancel.
    818   if (entry->will_process_pending_queue && entry->readers.empty())
    819     return;
    820 
    821   if (entry->writer) {
    822     DCHECK(trans == entry->writer);
    823 
    824     // Assume there was a failure.
    825     bool success = false;
    826     if (cancel) {
    827       DCHECK(entry->disk_entry);
    828       // This is a successful operation in the sense that we want to keep the
    829       // entry.
    830       success = trans->AddTruncatedFlag();
    831       // The previous operation may have deleted the entry.
    832       if (!trans->entry())
    833         return;
    834     }
    835     DoneWritingToEntry(entry, success);
    836   } else {
    837     DoneReadingFromEntry(entry, trans);
    838   }
    839 }
    840 
    841 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
    842   DCHECK(entry->readers.empty());
    843 
    844   entry->writer = NULL;
    845 
    846   if (success) {
    847     ProcessPendingQueue(entry);
    848   } else {
    849     DCHECK(!entry->will_process_pending_queue);
    850 
    851     // We failed to create this entry.
    852     TransactionList pending_queue;
    853     pending_queue.swap(entry->pending_queue);
    854 
    855     entry->disk_entry->Doom();
    856     DestroyEntry(entry);
    857 
    858     // We need to do something about these pending entries, which now need to
    859     // be added to a new entry.
    860     while (!pending_queue.empty()) {
    861       // ERR_CACHE_RACE causes the transaction to restart the whole process.
    862       pending_queue.front()->io_callback().Run(ERR_CACHE_RACE);
    863       pending_queue.pop_front();
    864     }
    865   }
    866 }
    867 
    868 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
    869   DCHECK(!entry->writer);
    870 
    871   TransactionList::iterator it =
    872       std::find(entry->readers.begin(), entry->readers.end(), trans);
    873   DCHECK(it != entry->readers.end());
    874 
    875   entry->readers.erase(it);
    876 
    877   ProcessPendingQueue(entry);
    878 }
    879 
    880 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
    881   DCHECK(entry->writer);
    882   DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
    883   DCHECK(entry->readers.empty());
    884 
    885   Transaction* trans = entry->writer;
    886 
    887   entry->writer = NULL;
    888   entry->readers.push_back(trans);
    889 
    890   ProcessPendingQueue(entry);
    891 }
    892 
    893 LoadState HttpCache::GetLoadStateForPendingTransaction(
    894       const Transaction* trans) {
    895   ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
    896   if (i == active_entries_.end()) {
    897     // If this is really a pending transaction, and it is not part of
    898     // active_entries_, we should be creating the backend or the entry.
    899     return LOAD_STATE_WAITING_FOR_CACHE;
    900   }
    901 
    902   Transaction* writer = i->second->writer;
    903   return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE;
    904 }
    905 
    906 void HttpCache::RemovePendingTransaction(Transaction* trans) {
    907   ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
    908   bool found = false;
    909   if (i != active_entries_.end())
    910     found = RemovePendingTransactionFromEntry(i->second, trans);
    911 
    912   if (found)
    913     return;
    914 
    915   if (building_backend_) {
    916     PendingOpsMap::const_iterator j = pending_ops_.find(std::string());
    917     if (j != pending_ops_.end())
    918       found = RemovePendingTransactionFromPendingOp(j->second, trans);
    919 
    920     if (found)
    921       return;
    922   }
    923 
    924   PendingOpsMap::const_iterator j = pending_ops_.find(trans->key());
    925   if (j != pending_ops_.end())
    926     found = RemovePendingTransactionFromPendingOp(j->second, trans);
    927 
    928   if (found)
    929     return;
    930 
    931   ActiveEntriesSet::iterator k = doomed_entries_.begin();
    932   for (; k != doomed_entries_.end() && !found; ++k)
    933     found = RemovePendingTransactionFromEntry(*k, trans);
    934 
    935   DCHECK(found) << "Pending transaction not found";
    936 }
    937 
    938 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
    939                                                   Transaction* trans) {
    940   TransactionList& pending_queue = entry->pending_queue;
    941 
    942   TransactionList::iterator j =
    943       find(pending_queue.begin(), pending_queue.end(), trans);
    944   if (j == pending_queue.end())
    945     return false;
    946 
    947   pending_queue.erase(j);
    948   return true;
    949 }
    950 
    951 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op,
    952                                                       Transaction* trans) {
    953   if (pending_op->writer->Matches(trans)) {
    954     pending_op->writer->ClearTransaction();
    955     pending_op->writer->ClearEntry();
    956     return true;
    957   }
    958   WorkItemList& pending_queue = pending_op->pending_queue;
    959 
    960   WorkItemList::iterator it = pending_queue.begin();
    961   for (; it != pending_queue.end(); ++it) {
    962     if ((*it)->Matches(trans)) {
    963       delete *it;
    964       pending_queue.erase(it);
    965       return true;
    966     }
    967   }
    968   return false;
    969 }
    970 
    971 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
    972   // Multiple readers may finish with an entry at once, so we want to batch up
    973   // calls to OnProcessPendingQueue.  This flag also tells us that we should
    974   // not delete the entry before OnProcessPendingQueue runs.
    975   if (entry->will_process_pending_queue)
    976     return;
    977   entry->will_process_pending_queue = true;
    978 
    979   base::MessageLoop::current()->PostTask(
    980       FROM_HERE,
    981       base::Bind(&HttpCache::OnProcessPendingQueue, AsWeakPtr(), entry));
    982 }
    983 
    984 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
    985   entry->will_process_pending_queue = false;
    986   DCHECK(!entry->writer);
    987 
    988   // If no one is interested in this entry, then we can deactivate it.
    989   if (entry->pending_queue.empty()) {
    990     if (entry->readers.empty())
    991       DestroyEntry(entry);
    992     return;
    993   }
    994 
    995   // Promote next transaction from the pending queue.
    996   Transaction* next = entry->pending_queue.front();
    997   if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
    998     return;  // Have to wait.
    999 
   1000   entry->pending_queue.erase(entry->pending_queue.begin());
   1001 
   1002   int rv = AddTransactionToEntry(entry, next);
   1003   if (rv != ERR_IO_PENDING) {
   1004     next->io_callback().Run(rv);
   1005   }
   1006 }
   1007 
   1008 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) {
   1009   WorkItemOperation op = pending_op->writer->operation();
   1010 
   1011   // Completing the creation of the backend is simpler than the other cases.
   1012   if (op == WI_CREATE_BACKEND)
   1013     return OnBackendCreated(result, pending_op);
   1014 
   1015   scoped_ptr<WorkItem> item(pending_op->writer);
   1016   bool fail_requests = false;
   1017 
   1018   ActiveEntry* entry = NULL;
   1019   std::string key;
   1020   if (result == OK) {
   1021     if (op == WI_DOOM_ENTRY) {
   1022       // Anything after a Doom has to be restarted.
   1023       fail_requests = true;
   1024     } else if (item->IsValid()) {
   1025       key = pending_op->disk_entry->GetKey();
   1026       entry = ActivateEntry(pending_op->disk_entry);
   1027     } else {
   1028       // The writer transaction is gone.
   1029       if (op == WI_CREATE_ENTRY)
   1030         pending_op->disk_entry->Doom();
   1031       pending_op->disk_entry->Close();
   1032       pending_op->disk_entry = NULL;
   1033       fail_requests = true;
   1034     }
   1035   }
   1036 
   1037   // We are about to notify a bunch of transactions, and they may decide to
   1038   // re-issue a request (or send a different one). If we don't delete
   1039   // pending_op, the new request will be appended to the end of the list, and
   1040   // we'll see it again from this point before it has a chance to complete (and
   1041   // we'll be messing out the request order). The down side is that if for some
   1042   // reason notifying request A ends up cancelling request B (for the same key),
   1043   // we won't find request B anywhere (because it would be in a local variable
   1044   // here) and that's bad. If there is a chance for that to happen, we'll have
   1045   // to move the callback used to be a CancelableCallback. By the way, for this
   1046   // to happen the action (to cancel B) has to be synchronous to the
   1047   // notification for request A.
   1048   WorkItemList pending_items;
   1049   pending_items.swap(pending_op->pending_queue);
   1050   DeletePendingOp(pending_op);
   1051 
   1052   item->NotifyTransaction(result, entry);
   1053 
   1054   while (!pending_items.empty()) {
   1055     item.reset(pending_items.front());
   1056     pending_items.pop_front();
   1057 
   1058     if (item->operation() == WI_DOOM_ENTRY) {
   1059       // A queued doom request is always a race.
   1060       fail_requests = true;
   1061     } else if (result == OK) {
   1062       entry = FindActiveEntry(key);
   1063       if (!entry)
   1064         fail_requests = true;
   1065     }
   1066 
   1067     if (fail_requests) {
   1068       item->NotifyTransaction(ERR_CACHE_RACE, NULL);
   1069       continue;
   1070     }
   1071 
   1072     if (item->operation() == WI_CREATE_ENTRY) {
   1073       if (result == OK) {
   1074         // A second Create request, but the first request succeeded.
   1075         item->NotifyTransaction(ERR_CACHE_CREATE_FAILURE, NULL);
   1076       } else {
   1077         if (op != WI_CREATE_ENTRY) {
   1078           // Failed Open followed by a Create.
   1079           item->NotifyTransaction(ERR_CACHE_RACE, NULL);
   1080           fail_requests = true;
   1081         } else {
   1082           item->NotifyTransaction(result, entry);
   1083         }
   1084       }
   1085     } else {
   1086       if (op == WI_CREATE_ENTRY && result != OK) {
   1087         // Failed Create followed by an Open.
   1088         item->NotifyTransaction(ERR_CACHE_RACE, NULL);
   1089         fail_requests = true;
   1090       } else {
   1091         item->NotifyTransaction(result, entry);
   1092       }
   1093     }
   1094   }
   1095 }
   1096 
   1097 // static
   1098 void HttpCache::OnPendingOpComplete(const base::WeakPtr<HttpCache>& cache,
   1099                                     PendingOp* pending_op,
   1100                                     int rv) {
   1101   if (cache.get()) {
   1102     cache->OnIOComplete(rv, pending_op);
   1103   } else {
   1104     // The callback was cancelled so we should delete the pending_op that
   1105     // was used with this callback.
   1106     delete pending_op;
   1107   }
   1108 }
   1109 
   1110 void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) {
   1111   scoped_ptr<WorkItem> item(pending_op->writer);
   1112   WorkItemOperation op = item->operation();
   1113   DCHECK_EQ(WI_CREATE_BACKEND, op);
   1114 
   1115   // We don't need the callback anymore.
   1116   pending_op->callback.Reset();
   1117 
   1118   if (backend_factory_.get()) {
   1119     // We may end up calling OnBackendCreated multiple times if we have pending
   1120     // work items. The first call saves the backend and releases the factory,
   1121     // and the last call clears building_backend_.
   1122     backend_factory_.reset();  // Reclaim memory.
   1123     if (result == OK)
   1124       disk_cache_ = pending_op->backend.Pass();
   1125   }
   1126 
   1127   if (!pending_op->pending_queue.empty()) {
   1128     WorkItem* pending_item = pending_op->pending_queue.front();
   1129     pending_op->pending_queue.pop_front();
   1130     DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation());
   1131 
   1132     // We want to process a single callback at a time, because the cache may
   1133     // go away from the callback.
   1134     pending_op->writer = pending_item;
   1135 
   1136     base::MessageLoop::current()->PostTask(
   1137         FROM_HERE,
   1138         base::Bind(
   1139             &HttpCache::OnBackendCreated, AsWeakPtr(), result, pending_op));
   1140   } else {
   1141     building_backend_ = false;
   1142     DeletePendingOp(pending_op);
   1143   }
   1144 
   1145   // The cache may be gone when we return from the callback.
   1146   if (!item->DoCallback(result, disk_cache_.get()))
   1147     item->NotifyTransaction(result, NULL);
   1148 }
   1149 
   1150 }  // namespace net
   1151