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