Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / http / http_cache.cc
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
47 namespace {
48
49 bool UseCertCache() {
50   return base::FieldTrialList::FindFullName("CertCacheTrial") ==
51          "ExperimentGroup";
52 }
53
54 // Adaptor to delete a file on a worker thread.
55 void DeletePath(base::FilePath path) {
56   base::DeleteFile(path, false);
57 }
58
59 }  // namespace
60
61 namespace net {
62
63 HttpCache::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
76 HttpCache::DefaultBackend::~DefaultBackend() {}
77
78 // static
79 HttpCache::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
84 int 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
101 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry)
102     : disk_entry(entry),
103       writer(NULL),
104       will_process_pending_queue(false),
105       doomed(false) {
106 }
107
108 HttpCache::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.
119 struct 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.
133 enum 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.
142 class 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.
198 class 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
226 void 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
249 void 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
267 void HttpCache::MetadataWriter::SelfDestroy() {
268   delete this;
269 }
270
271 void HttpCache::MetadataWriter::OnIOComplete(int result) {
272   if (!verified_)
273     return VerifyResponse(result);
274   SelfDestroy();
275 }
276
277 //-----------------------------------------------------------------------------
278
279 class 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 //-----------------------------------------------------------------------------
295 HttpCache::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.
310 HttpCache::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
321 HttpCache::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
334 HttpCache::~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
383 int 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
395 disk_cache::Backend* HttpCache::GetCurrentBackend() const {
396   return disk_cache_.get();
397 }
398
399 // static
400 bool 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
407 void 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
429 void HttpCache::CloseAllConnections() {
430   HttpNetworkSession* session = GetSession();
431   if (session)
432     session->CloseAllConnections();
433 }
434
435 void HttpCache::CloseIdleConnections() {
436   HttpNetworkSession* session = GetSession();
437   if (session)
438     session->CloseIdleConnections();
439 }
440
441 void 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
453 void 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
459 int 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
476 HttpCache* HttpCache::GetCache() {
477   return this;
478 }
479
480 HttpNetworkSession* HttpCache::GetSession() {
481   return network_layer_->GetSession();
482 }
483
484 scoped_ptr<HttpTransactionFactory>
485 HttpCache::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
494 int 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
529 int 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.
545 std::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
584 void 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
595 int 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
621 int 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
644 void 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
661 void 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
674 HttpCache::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
679 HttpCache::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
687 void 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.
708 void 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
719 HttpCache::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
731 void 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
754 int 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
785 int 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
814 void HttpCache::DestroyEntry(ActiveEntry* entry) {
815   if (entry->doomed) {
816     FinalizeDoomedEntry(entry);
817   } else {
818     DeactivateEntry(entry);
819   }
820 }
821
822 int 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
861 void 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
888 void 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
915 void 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
927 void 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
940 LoadState 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
953 void 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
985 bool 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
998 bool 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
1018 void 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
1028 void 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
1041 void 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
1065 void 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
1155 void 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
1167 void 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