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