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