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