diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_error_list.h | 12 | ||||
-rw-r--r-- | net/disk_cache/backend_impl.cc | 8 | ||||
-rw-r--r-- | net/disk_cache/backend_impl.h | 1 | ||||
-rw-r--r-- | net/disk_cache/disk_cache.h | 7 | ||||
-rw-r--r-- | net/disk_cache/mem_backend_impl.cc | 8 | ||||
-rw-r--r-- | net/disk_cache/mem_backend_impl.h | 1 | ||||
-rw-r--r-- | net/http/http_cache.cc | 325 | ||||
-rw-r--r-- | net/http/http_cache.h | 98 | ||||
-rw-r--r-- | net/http/http_cache_transaction.cc | 96 | ||||
-rw-r--r-- | net/http/http_cache_transaction.h | 9 | ||||
-rw-r--r-- | net/http/http_cache_unittest.cc | 318 |
11 files changed, 730 insertions, 153 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 3bc2c3e..4003ee0 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -302,5 +302,17 @@ NET_ERROR(CACHE_READ_FAILURE, -401) // The operation is not supported for this entry. NET_ERROR(CACHE_OPERATION_NOT_SUPPORTED, -403) +// The disk cache is unable to open this entry. +NET_ERROR(CACHE_OPEN_FAILURE, -404) + +// The disk cache is unable to create this entry. +NET_ERROR(CACHE_CREATE_FAILURE, -405) + +// Multiple transactions are racing to create disk cache entries. This is an +// internal error returned from the HttpCache to the HttpCacheTransaction that +// tells the transaction to restart the entry-creation logic because the state +// of the cache has changed. +NET_ERROR(CACHE_RACE, -406) + // The server's response was insecure (e.g. there was a cert error). NET_ERROR(INSECURE_RESPONSE, -501) diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 9ab3271..3b3ca6a 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -494,6 +494,14 @@ bool BackendImpl::DoomEntry(const std::string& key) { return true; } +int BackendImpl::DoomEntry(const std::string& key, + CompletionCallback* callback) { + if (DoomEntry(key)) + return net::OK; + + return net::ERR_FAILED; +} + bool BackendImpl::DoomAllEntries() { if (!num_refs_) { PrepareForRestart(); diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h index b9a288f..6267fac 100644 --- a/net/disk_cache/backend_impl.h +++ b/net/disk_cache/backend_impl.h @@ -68,6 +68,7 @@ class BackendImpl : public Backend { virtual int CreateEntry(const std::string& key, Entry** entry, CompletionCallback* callback); virtual bool DoomEntry(const std::string& key); + virtual int DoomEntry(const std::string& key, CompletionCallback* callback); virtual bool DoomAllEntries(); virtual int DoomAllEntries(CompletionCallback* callback); virtual bool DoomEntriesBetween(const base::Time initial_time, diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h index c47bd47..3d2793b 100644 --- a/net/disk_cache/disk_cache.h +++ b/net/disk_cache/disk_cache.h @@ -113,8 +113,15 @@ class Backend { CompletionCallback* callback) = 0; // Marks the entry, specified by the given key, for deletion. + // Note: This method is deprecated. virtual bool DoomEntry(const std::string& key) = 0; + // Marks the entry, specified by the given key, for deletion. The return value + // is a net error code. If this method returns ERR_IO_PENDING, the |callback| + // will be invoked after the entry is doomed. + virtual int DoomEntry(const std::string& key, + CompletionCallback* callback) = 0; + // Marks all entries for deletion. // Note: This method is deprecated. virtual bool DoomAllEntries() = 0; diff --git a/net/disk_cache/mem_backend_impl.cc b/net/disk_cache/mem_backend_impl.cc index 0b0d7bd..875efdc 100644 --- a/net/disk_cache/mem_backend_impl.cc +++ b/net/disk_cache/mem_backend_impl.cc @@ -144,6 +144,14 @@ bool MemBackendImpl::DoomEntry(const std::string& key) { return true; } +int MemBackendImpl::DoomEntry(const std::string& key, + CompletionCallback* callback) { + if (DoomEntry(key)) + return net::OK; + + return net::ERR_FAILED; +} + void MemBackendImpl::InternalDoomEntry(MemEntryImpl* entry) { // Only parent entries can be passed into this method. DCHECK(entry->type() == MemEntryImpl::kParentEntry); diff --git a/net/disk_cache/mem_backend_impl.h b/net/disk_cache/mem_backend_impl.h index 5c9899e..48d196c 100644 --- a/net/disk_cache/mem_backend_impl.h +++ b/net/disk_cache/mem_backend_impl.h @@ -35,6 +35,7 @@ class MemBackendImpl : public Backend { virtual int CreateEntry(const std::string& key, Entry** entry, CompletionCallback* callback); virtual bool DoomEntry(const std::string& key); + virtual int DoomEntry(const std::string& key, CompletionCallback* callback); virtual bool DoomAllEntries(); virtual int DoomAllEntries(CompletionCallback* callback); virtual bool DoomEntriesBetween(const base::Time initial_time, diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 8a76ad1..e2d0e2c 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -52,6 +52,78 @@ HttpCache::ActiveEntry::~ActiveEntry() { //----------------------------------------------------------------------------- +// This structure keeps track of work items that are attempting to create or +// open cache entries. +struct HttpCache::NewEntry { + NewEntry() : disk_entry(NULL), writer(NULL) {} + ~NewEntry() {} + + disk_cache::Entry* disk_entry; + WorkItem* writer; + WorkItemList pending_queue; +}; + +//----------------------------------------------------------------------------- + +// The type of operation represented by a work item. +enum WorkItemOperation { + WI_OPEN_ENTRY, + WI_CREATE_ENTRY, + WI_DOOM_ENTRY +}; + +// A work item encapsulates a single request for cache entry with all the +// information needed to complete that request. +class HttpCache::WorkItem { + public: + WorkItem(ActiveEntry** entry, CompletionCallback* callback, + WorkItemOperation operation) + : entry_(entry), callback_(callback), operation_(operation) {} + ~WorkItem() {} + WorkItemOperation operation() { return operation_; } + + // Calls back the transaction with the result of the operation. + void NotifyTransaction(int result, ActiveEntry* entry) { + if (entry_) + *entry_ = entry; + if (callback_) + callback_->Run(result); + } + + void ClearCallback() { callback_ = NULL; } + void ClearEntry() { entry_ = NULL; } + bool Matches(CompletionCallback* cb) const { return cb == callback_; } + bool IsValid() const { return callback_ || entry_; } + + private: + ActiveEntry** entry_; + CompletionCallback* callback_; + WorkItemOperation operation_; +}; + +//----------------------------------------------------------------------------- + +// This class is a specialized type of CompletionCallback that allows us to +// pass multiple arguments to the completion routine. +class HttpCache::BackendCallback : public CallbackRunner<Tuple1<int> > { + public: + BackendCallback(HttpCache* cache, NewEntry* entry) + : cache_(cache), entry_(entry) {} + ~BackendCallback() {} + + virtual void RunWithParams(const Tuple1<int>& params) { + cache_->OnIOComplete(params.a, entry_); + delete this; + } + + private: + HttpCache* cache_; + NewEntry* entry_; + DISALLOW_COPY_AND_ASSIGN(BackendCallback); +}; + +//----------------------------------------------------------------------------- + HttpCache::HttpCache(HostResolver* host_resolver, ProxyService* proxy_service, SSLConfigService* ssl_config_service, @@ -242,27 +314,52 @@ std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) { return result; } -void HttpCache::DoomEntry(const std::string& key) { +int HttpCache::DoomEntry(const std::string& key, CompletionCallback* callback) { // Need to abandon the ActiveEntry, but any transaction attached to the entry // should not be impacted. Dooming an entry only means that it will no // longer be returned by FindActiveEntry (and it will also be destroyed once // all consumers are finished with the entry). ActiveEntriesMap::iterator it = active_entries_.find(key); if (it == active_entries_.end()) { - disk_cache_->DoomEntry(key); - } else { - ActiveEntry* entry = it->second; - active_entries_.erase(it); + return AsyncDoomEntry(key, callback); + } - // We keep track of doomed entries so that we can ensure that they are - // cleaned up properly when the cache is destroyed. - doomed_entries_.insert(entry); + ActiveEntry* entry = it->second; + active_entries_.erase(it); - entry->disk_entry->Doom(); - entry->doomed = true; + // We keep track of doomed entries so that we can ensure that they are + // cleaned up properly when the cache is destroyed. + doomed_entries_.insert(entry); - DCHECK(entry->writer || !entry->readers.empty()); + entry->disk_entry->Doom(); + entry->doomed = true; + + DCHECK(entry->writer || !entry->readers.empty()); + return OK; +} + +int HttpCache::AsyncDoomEntry(const std::string& key, + CompletionCallback* callback) { + DCHECK(callback); + WorkItem* item = new WorkItem(NULL, callback, WI_DOOM_ENTRY); + NewEntry* new_entry = GetNewEntry(key); + if (new_entry->writer) { + new_entry->pending_queue.push_back(item); + return ERR_IO_PENDING; } + + DCHECK(new_entry->pending_queue.empty()); + + new_entry->writer = item; + BackendCallback* my_callback = new BackendCallback(this, new_entry); + + int rv = disk_cache_->DoomEntry(key, my_callback); + if (rv != ERR_IO_PENDING) { + item->ClearCallback(); + my_callback->Run(rv); + } + + return rv; } void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { @@ -283,24 +380,92 @@ HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { return it != active_entries_.end() ? it->second : NULL; } -HttpCache::ActiveEntry* HttpCache::OpenEntry(const std::string& key) { +HttpCache::NewEntry* HttpCache::GetNewEntry(const std::string& key) { DCHECK(!FindActiveEntry(key)); - disk_cache::Entry* disk_entry; - if (!disk_cache_->OpenEntry(key, &disk_entry)) - return NULL; + NewEntriesMap::const_iterator it = new_entries_.find(key); + if (it != new_entries_.end()) + return it->second; + + NewEntry* entry = new NewEntry(); + new_entries_[key] = entry; + return entry; +} + +void HttpCache::DeleteNewEntry(NewEntry* entry) { + std::string key; + if (entry->disk_entry) + key = entry->disk_entry->GetKey(); + + if (!key.empty()) { + NewEntriesMap::iterator it = new_entries_.find(key); + DCHECK(it != new_entries_.end()); + new_entries_.erase(it); + } else { + for (NewEntriesMap::iterator it = new_entries_.begin(); + it != new_entries_.end(); ++it) { + if (it->second == entry) { + new_entries_.erase(it); + break; + } + } + } + + delete entry; +} + +int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry, + CompletionCallback* callback) { + ActiveEntry* active_entry = FindActiveEntry(key); + if (active_entry) { + *entry = active_entry; + return OK; + } + + WorkItem* item = new WorkItem(entry, callback, WI_OPEN_ENTRY); + NewEntry* new_entry = GetNewEntry(key); + if (new_entry->writer) { + new_entry->pending_queue.push_back(item); + return ERR_IO_PENDING; + } + + DCHECK(new_entry->pending_queue.empty()); + + new_entry->writer = item; + BackendCallback* my_callback = new BackendCallback(this, new_entry); - return ActivateEntry(key, disk_entry); + int rv = disk_cache_->OpenEntry(key, &(new_entry->disk_entry), my_callback); + if (rv != ERR_IO_PENDING) { + item->ClearCallback(); + my_callback->Run(rv); + } + + return rv; } -HttpCache::ActiveEntry* HttpCache::CreateEntry(const std::string& key) { +int HttpCache::CreateEntry(const std::string& key, ActiveEntry** entry, + CompletionCallback* callback) { DCHECK(!FindActiveEntry(key)); - disk_cache::Entry* disk_entry; - if (!disk_cache_->CreateEntry(key, &disk_entry)) - return NULL; + WorkItem* item = new WorkItem(entry, callback, WI_CREATE_ENTRY); + NewEntry* new_entry = GetNewEntry(key); + if (new_entry->writer) { + new_entry->pending_queue.push_back(item); + return ERR_IO_PENDING; + } + + DCHECK(new_entry->pending_queue.empty()); - return ActivateEntry(key, disk_entry); + new_entry->writer = item; + BackendCallback* my_callback = new BackendCallback(this, new_entry); + + int rv = disk_cache_->CreateEntry(key, &(new_entry->disk_entry), my_callback); + if (rv != ERR_IO_PENDING) { + item->ClearCallback(); + my_callback->Run(rv); + } + + return rv; } void HttpCache::DestroyEntry(ActiveEntry* entry) { @@ -314,6 +479,7 @@ void HttpCache::DestroyEntry(ActiveEntry* entry) { HttpCache::ActiveEntry* HttpCache::ActivateEntry( const std::string& key, disk_cache::Entry* disk_entry) { + DCHECK(!FindActiveEntry(key)); ActiveEntry* entry = new ActiveEntry(disk_entry); active_entries_[key] = entry; return entry; @@ -463,7 +629,8 @@ void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { ProcessPendingQueue(entry); } -void HttpCache::RemovePendingTransaction(Transaction* trans) { +void HttpCache::RemovePendingTransaction(Transaction* trans, + CompletionCallback* cb) { ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key()); bool found = false; if (i != active_entries_.end()) @@ -472,9 +639,15 @@ void HttpCache::RemovePendingTransaction(Transaction* trans) { if (found) return; - ActiveEntriesSet::iterator it = doomed_entries_.begin(); - for (; it != doomed_entries_.end() && !found; ++it) - found = RemovePendingTransactionFromEntry(*it, trans); + NewEntriesMap::const_iterator j = new_entries_.find(trans->key()); + if (j != new_entries_.end()) + found = RemovePendingCallbackFromNewEntry(j->second, cb); + + ActiveEntriesSet::iterator k = doomed_entries_.begin(); + for (; k != doomed_entries_.end() && !found; ++k) + found = RemovePendingTransactionFromEntry(*k, trans); + + DCHECK(found) << "Pending transaction not found"; } bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, @@ -490,6 +663,25 @@ bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, return true; } +bool HttpCache::RemovePendingCallbackFromNewEntry(NewEntry* entry, + CompletionCallback* cb) { + if (entry->writer->Matches(cb)) { + entry->writer->ClearCallback(); + entry->writer->ClearEntry(); + return true; + } + WorkItemList& pending_queue = entry->pending_queue; + + WorkItemList::iterator it = pending_queue.begin(); + for (; it != pending_queue.end(); ++it) { + if ((*it)->Matches(cb)) { + pending_queue.erase(it); + return true; + } + } + return false; +} + void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { // Multiple readers may finish with an entry at once, so we want to batch up // calls to OnProcessPendingQueue. This flag also tells us that we should @@ -524,6 +716,89 @@ void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { AddTransactionToEntry(entry, next); } +void HttpCache::OnIOComplete(int result, NewEntry* new_entry) { + scoped_ptr<WorkItem> item(new_entry->writer); + WorkItemOperation op = item->operation(); + bool fail_requests = false; + + ActiveEntry* entry = NULL; + std::string key; + if (result == OK) { + if (op == WI_DOOM_ENTRY) { + // Anything after a Doom has to be restarted. + fail_requests = true; + } else if (item->IsValid()) { + key = new_entry->disk_entry->GetKey(); + entry = ActivateEntry(key, new_entry->disk_entry); + } else { + // The writer transaction is gone. + if (op == WI_CREATE_ENTRY) + new_entry->disk_entry->Doom(); + new_entry->disk_entry->Close(); + fail_requests = true; + } + } + + // We are about to notify a bunch of transactions, and they may decide to + // re-issue a request (or send a different one). If we don't delete new_entry, + // the new request will be appended to the end of the list, and we'll see it + // again from this point before it has a chance to complete (and we'll be + // messing out the request order). The down side is that if for some reason + // notifying request A ends up cancelling request B (for the same key), we + // won't find request B anywhere (because it would be in a local variable + // here) and that's bad. If there is a chance for that to happen, we'll have + // to move the callback used to be a CancelableCallback. By the way, for this + // to happen the action (to cancel B) has to be synchronous to the + // notification for request A. + WorkItemList pending_items; + pending_items.swap(new_entry->pending_queue); + DeleteNewEntry(new_entry); + + item->NotifyTransaction(result, entry); + + while (!pending_items.empty()) { + item.reset(pending_items.front()); + pending_items.pop_front(); + + if (item->operation() == WI_DOOM_ENTRY) { + // A queued doom request is always a race. + fail_requests = true; + } else if (result == OK) { + entry = FindActiveEntry(key); + if (!entry) + fail_requests = true; + } + + if (fail_requests) { + item->NotifyTransaction(ERR_CACHE_RACE, NULL); + continue; + } + + if (item->operation() == WI_CREATE_ENTRY) { + if (result == OK) { + // A second Create request, but the first request succeded. + item->NotifyTransaction(ERR_CACHE_CREATE_FAILURE, NULL); + } else { + if (op != WI_CREATE_ENTRY) { + // Failed Open followed by a Create. + item->NotifyTransaction(ERR_CACHE_RACE, NULL); + fail_requests = true; + } else { + item->NotifyTransaction(result, entry); + } + } + } else { + if (op == WI_CREATE_ENTRY && result != OK) { + // Failed Create followed by an Open. + item->NotifyTransaction(ERR_CACHE_RACE, NULL); + fail_requests = true; + } else { + item->NotifyTransaction(result, entry); + } + } + } +} + void HttpCache::CloseCurrentConnections() { net::HttpNetworkLayer* network = static_cast<net::HttpNetworkLayer*>(network_layer_.get()); diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 6cd8718..90dac74 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -24,6 +24,7 @@ #include "base/task.h" #include "base/weak_ptr.h" #include "net/base/cache_type.h" +#include "net/base/completion_callback.h" #include "net/http/http_transaction_factory.h" namespace disk_cache { @@ -145,10 +146,14 @@ class HttpCache : public HttpTransactionFactory, // Types -------------------------------------------------------------------- + class BackendCallback; class Transaction; + class WorkItem; friend class Transaction; + struct NewEntry; // Info for an entry under construction. typedef std::list<Transaction*> TransactionList; + typedef std::list<WorkItem*> WorkItemList; struct ActiveEntry { disk_cache::Entry* disk_entry; @@ -163,40 +168,112 @@ class HttpCache : public HttpTransactionFactory, }; typedef base::hash_map<std::string, ActiveEntry*> ActiveEntriesMap; + typedef base::hash_map<std::string, NewEntry*> NewEntriesMap; typedef std::set<ActiveEntry*> ActiveEntriesSet; // Methods ------------------------------------------------------------------ + // Generates the cache key for this request. std::string GenerateCacheKey(const HttpRequestInfo*); - void DoomEntry(const std::string& key); + + // Dooms the entry selected by |key|. |callback| is used for completion + // notification if this function returns ERR_IO_PENDING. The entry can be + // currently in use or not. + int DoomEntry(const std::string& key, CompletionCallback* callback); + + // Dooms the entry selected by |key|. |callback| is used for completion + // notification if this function returns ERR_IO_PENDING. The entry should not + // be currently in use. + int AsyncDoomEntry(const std::string& key, CompletionCallback* callback); + + // Closes a previously doomed entry. void FinalizeDoomedEntry(ActiveEntry* entry); + + // Returns an entry that is currently in use and not doomed, or NULL. ActiveEntry* FindActiveEntry(const std::string& key); - ActiveEntry* ActivateEntry(const std::string& key, disk_cache::Entry*); + + // Creates a new ActiveEntry and starts tracking it. |disk_entry| is the disk + // cache entry that corresponds to the desired |key|. + // TODO(rvargas): remove the |key| argument. + ActiveEntry* ActivateEntry(const std::string& key, + disk_cache::Entry* disk_entry); + + // Deletes an ActiveEntry. void DeactivateEntry(ActiveEntry* entry); + + // Deletes an ActiveEntry using an exhaustive search. void SlowDeactivateEntry(ActiveEntry* entry); - ActiveEntry* OpenEntry(const std::string& key); - ActiveEntry* CreateEntry(const std::string& cache_key); + + // Returns the NewEntry for the desired |key|. If an entry is not under + // construction already, a new NewEntry structure is created. + NewEntry* GetNewEntry(const std::string& key); + + // Deletes a NewEntry. + void DeleteNewEntry(NewEntry* entry); + + // Opens the disk cache entry associated with |key|, returning an ActiveEntry + // in |*entry|. |callback| is used for completion notification if this + // function returns ERR_IO_PENDING. + int OpenEntry(const std::string& key, ActiveEntry** entry, + CompletionCallback* callback); + + // Creates the disk cache entry associated with |key|, returning an + // ActiveEntry in |*entry|. |callback| is used for completion notification if + // this function returns ERR_IO_PENDING. + int CreateEntry(const std::string& key, ActiveEntry** entry, + CompletionCallback* callback); + + // Destroys an ActiveEntry (active or doomed). void DestroyEntry(ActiveEntry* entry); + + // Adds a transaction to an ActiveEntry. int AddTransactionToEntry(ActiveEntry* entry, Transaction* trans); + + // Called when the transaction has finished working with this entry. |cancel| + // is true if the operation was cancelled by the caller instead of running + // to completion. void DoneWithEntry(ActiveEntry* entry, Transaction* trans, bool cancel); + + // Called when the transaction has finished writting to this entry. |success| + // is false if the cache entry should be deleted. void DoneWritingToEntry(ActiveEntry* entry, bool success); + + // Called when the transaction has finished reading from this entry. void DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans); + + // Convers the active writter transaction to a reader so that other + // transactions can start reading from this entry. void ConvertWriterToReader(ActiveEntry* entry); - void RemovePendingTransaction(Transaction* trans); + + // Removes the transaction |trans|, waiting for |callback|, from the pending + // list of an entry (NewEntry, active or doomed entry). + void RemovePendingTransaction(Transaction* trans, CompletionCallback* cb); + + // Removes the transaction |trans|, from the pending list of |entry|. bool RemovePendingTransactionFromEntry(ActiveEntry* entry, Transaction* trans); - void ProcessPendingQueue(ActiveEntry* entry); + // Removes the callback |cb|, from the pending list of |entry|. + bool RemovePendingCallbackFromNewEntry(NewEntry* entry, + CompletionCallback* cb); + + // Resumes processing the pending list of |entry|. + void ProcessPendingQueue(ActiveEntry* entry); // Events (called via PostTask) --------------------------------------------- void OnProcessPendingQueue(ActiveEntry* entry); + // Callbacks ---------------------------------------------------------------- + + // Processes BackendCallback notifications. + void OnIOComplete(int result, NewEntry* entry); + // Variables ---------------------------------------------------------------- - // used when lazily constructing the disk_cache_ + // Used when lazily constructing the disk_cache_. FilePath disk_cache_dir_; Mode mode_; @@ -205,12 +282,15 @@ class HttpCache : public HttpTransactionFactory, scoped_ptr<HttpTransactionFactory> network_layer_; scoped_ptr<disk_cache::Backend> disk_cache_; - // The set of active entries indexed by cache key + // The set of active entries indexed by cache key. ActiveEntriesMap active_entries_; - // The set of doomed entries + // The set of doomed entries. ActiveEntriesSet doomed_entries_; + // The set of entries "under construction". + NewEntriesMap new_entries_; + ScopedRunnableMethodFactory<HttpCache> task_factory_; bool enable_range_support_; diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index d8c51ae..733b2e1 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -113,11 +113,12 @@ HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support) enable_range_support_(enable_range_support), truncated_(false), server_responded_206_(false), + cache_pending_(false), read_offset_(0), effective_load_flags_(0), final_upload_progress_(0), ALLOW_THIS_IN_INITIALIZER_LIST( - network_callback_(this, &Transaction::OnIOComplete)), + io_callback_(this, &Transaction::OnIOComplete)), ALLOW_THIS_IN_INITIALIZER_LIST( cache_callback_(new CancelableCompletionCallback<Transaction>( this, &Transaction::OnIOComplete))), @@ -142,8 +143,8 @@ HttpCache::Transaction::~Transaction() { } cache_->DoneWithEntry(entry_, this, cancel_request); - } else { - cache_->RemovePendingTransaction(this); + } else if (cache_pending_) { + cache_->RemovePendingTransaction(this, &io_callback_); } } @@ -363,6 +364,7 @@ uint64 HttpCache::Transaction::GetUploadProgress() const { int HttpCache::Transaction::AddToEntry() { next_state_ = STATE_INIT_ENTRY; + cache_pending_ = false; return DoLoop(OK); } @@ -377,47 +379,50 @@ int HttpCache::Transaction::DoInitEntry() { return OK; } - new_entry_ = cache_->FindActiveEntry(cache_key_); - if (!new_entry_) { - next_state_ = STATE_OPEN_ENTRY; - return OK; - } - - if (mode_ == WRITE) { - next_state_ = STATE_CREATE_ENTRY; - return OK; - } - - next_state_ = STATE_ADD_TO_ENTRY; + next_state_ = STATE_OPEN_ENTRY; return OK; } int HttpCache::Transaction::DoDoomEntry() { next_state_ = STATE_DOOM_ENTRY_COMPLETE; - cache_->DoomEntry(cache_key_); - return OK; + cache_pending_ = true; + // TODO(rvargas): Add a LoadLog event. + return cache_->DoomEntry(cache_key_, &io_callback_); } -int HttpCache::Transaction::DoDoomEntryComplete() { +int HttpCache::Transaction::DoDoomEntryComplete(int result) { next_state_ = STATE_CREATE_ENTRY; + cache_pending_ = false; + if (result == ERR_CACHE_RACE) + next_state_ = STATE_INIT_ENTRY; + return OK; } int HttpCache::Transaction::DoOpenEntry() { DCHECK(!new_entry_); next_state_ = STATE_OPEN_ENTRY_COMPLETE; + cache_pending_ = true; LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY); - new_entry_ = cache_->OpenEntry(cache_key_); - return OK; + return cache_->OpenEntry(cache_key_, &new_entry_, &io_callback_); } -int HttpCache::Transaction::DoOpenEntryComplete() { +int HttpCache::Transaction::DoOpenEntryComplete(int result) { + // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is + // OK, otherwise the cache will end up with an active entry without any + // transaction attached. LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY); - if (new_entry_) { + cache_pending_ = false; + if (result == OK) { next_state_ = STATE_ADD_TO_ENTRY; return OK; } + if (result == ERR_CACHE_RACE) { + next_state_ = STATE_INIT_ENTRY; + return OK; + } + if (mode_ == READ_WRITE) { mode_ = WRITE; next_state_ = STATE_CREATE_ENTRY; @@ -440,15 +445,25 @@ int HttpCache::Transaction::DoOpenEntryComplete() { int HttpCache::Transaction::DoCreateEntry() { DCHECK(!new_entry_); next_state_ = STATE_CREATE_ENTRY_COMPLETE; + cache_pending_ = true; LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY); - new_entry_ = cache_->CreateEntry(cache_key_); - return OK; + return cache_->CreateEntry(cache_key_, &new_entry_, &io_callback_); } -int HttpCache::Transaction::DoCreateEntryComplete() { +int HttpCache::Transaction::DoCreateEntryComplete(int result) { + // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is + // OK, otherwise the cache will end up with an active entry without any + // transaction attached. LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY); + cache_pending_ = false; next_state_ = STATE_ADD_TO_ENTRY; - if (!new_entry_) { + + if (result == ERR_CACHE_RACE) { + next_state_ = STATE_INIT_ENTRY; + return OK; + } + + if (result != OK) { // We have a race here: Maybe we failed to open the entry and decided to // create one, but by the time we called create, another transaction already // created the entry. If we want to eliminate this issue, we need an atomic @@ -464,6 +479,7 @@ int HttpCache::Transaction::DoCreateEntryComplete() { int HttpCache::Transaction::DoAddToEntry() { DCHECK(new_entry_); + cache_pending_ = true; LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING); int rv = cache_->AddTransactionToEntry(new_entry_, this); new_entry_ = NULL; @@ -472,6 +488,7 @@ int HttpCache::Transaction::DoAddToEntry() { int HttpCache::Transaction::EntryAvailable(ActiveEntry* entry) { LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING); + cache_pending_ = false; entry_ = entry; next_state_ = STATE_ENTRY_AVAILABLE; @@ -613,24 +630,21 @@ int HttpCache::Transaction::DoLoop(int result) { rv = DoOpenEntry(); break; case STATE_OPEN_ENTRY_COMPLETE: - DCHECK_EQ(OK, rv); - rv = DoOpenEntryComplete(); + rv = DoOpenEntryComplete(rv); break; case STATE_CREATE_ENTRY: DCHECK_EQ(OK, rv); rv = DoCreateEntry(); break; case STATE_CREATE_ENTRY_COMPLETE: - DCHECK_EQ(OK, rv); - rv = DoCreateEntryComplete(); + rv = DoCreateEntryComplete(rv); break; case STATE_DOOM_ENTRY: DCHECK_EQ(OK, rv); rv = DoDoomEntry(); break; case STATE_DOOM_ENTRY_COMPLETE: - DCHECK_EQ(OK, rv); - rv = DoDoomEntryComplete(); + rv = DoDoomEntryComplete(rv); break; case STATE_ADD_TO_ENTRY: DCHECK_EQ(OK, rv); @@ -1032,7 +1046,7 @@ int HttpCache::Transaction::DoSendRequest() { return rv; next_state_ = STATE_SEND_REQUEST_COMPLETE; - rv = network_trans_->Start(request_, &network_callback_, load_log_); + rv = network_trans_->Start(request_, &io_callback_, load_log_); return rv; } @@ -1042,7 +1056,7 @@ int HttpCache::Transaction::RestartNetworkRequest() { DCHECK_EQ(STATE_NONE, next_state_); next_state_ = STATE_SEND_REQUEST_COMPLETE; - int rv = network_trans_->RestartIgnoringLastError(&network_callback_); + int rv = network_trans_->RestartIgnoringLastError(&io_callback_); if (rv != ERR_IO_PENDING) return DoLoop(rv); return rv; @@ -1055,8 +1069,7 @@ int HttpCache::Transaction::RestartNetworkRequestWithCertificate( DCHECK_EQ(STATE_NONE, next_state_); next_state_ = STATE_SEND_REQUEST_COMPLETE; - int rv = network_trans_->RestartWithCertificate(client_cert, - &network_callback_); + int rv = network_trans_->RestartWithCertificate(client_cert, &io_callback_); if (rv != ERR_IO_PENDING) return DoLoop(rv); return rv; @@ -1070,8 +1083,7 @@ int HttpCache::Transaction::RestartNetworkRequestWithAuth( DCHECK_EQ(STATE_NONE, next_state_); next_state_ = STATE_SEND_REQUEST_COMPLETE; - int rv = network_trans_->RestartWithAuth(username, password, - &network_callback_); + int rv = network_trans_->RestartWithAuth(username, password, &io_callback_); if (rv != ERR_IO_PENDING) return DoLoop(rv); return rv; @@ -1282,7 +1294,7 @@ int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { int HttpCache::Transaction::DoNetworkRead() { next_state_ = STATE_NETWORK_READ_COMPLETE; - return network_trans_->Read(read_buf_, io_buf_len_, &network_callback_); + return network_trans_->Read(read_buf_, io_buf_len_, &io_callback_); } int HttpCache::Transaction::ReadFromEntry(IOBuffer* data, int data_len) { @@ -1442,8 +1454,9 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) { } void HttpCache::Transaction::DoomPartialEntry(bool delete_object) { + int rv = cache_->DoomEntry(cache_key_, NULL); + DCHECK_EQ(OK, rv); cache_->DoneWithEntry(entry_, this, false); - cache_->DoomEntry(cache_key_); entry_ = NULL; if (delete_object) partial_.reset(NULL); @@ -1579,7 +1592,8 @@ int HttpCache::Transaction::DoUpdateCachedResponse() { response_.request_time = new_response_->request_time; if (response_.headers->HasHeaderValue("cache-control", "no-store")) { - cache_->DoomEntry(cache_key_); + int ret = cache_->DoomEntry(cache_key_, NULL); + DCHECK_EQ(OK, ret); } else { // If we are already reading, we already updated the headers for this // request; doing it again will change Content-Length. diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index 0e7e51c..f417378 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h @@ -150,11 +150,11 @@ class HttpCache::Transaction : public HttpTransaction { int DoNetworkReadComplete(int result); int DoInitEntry(); int DoOpenEntry(); - int DoOpenEntryComplete(); + int DoOpenEntryComplete(int result); int DoCreateEntry(); - int DoCreateEntryComplete(); + int DoCreateEntryComplete(int result); int DoDoomEntry(); - int DoDoomEntryComplete(); + int DoDoomEntryComplete(int result); int DoAddToEntry(); int DoEntryAvailable(); int DoPartialCacheValidation(); @@ -303,13 +303,14 @@ class HttpCache::Transaction : public HttpTransaction { bool enable_range_support_; bool truncated_; // We don't have all the response data. bool server_responded_206_; + bool cache_pending_; // We are waiting for the HttpCache. scoped_refptr<IOBuffer> read_buf_; int io_buf_len_; int read_offset_; int effective_load_flags_; scoped_ptr<PartialData> partial_; // We are dealing with range requests. uint64 final_upload_progress_; - CompletionCallbackImpl<Transaction> network_callback_; + CompletionCallbackImpl<Transaction> io_callback_; scoped_refptr<CancelableCompletionCallback<Transaction> > cache_callback_; scoped_refptr<CancelableCompletionCallback<Transaction> > write_headers_callback_; diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 8a69c65..72231fb 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -27,6 +27,26 @@ using base::Time; namespace { +int GetTestModeForEntry(const std::string& key) { + // 'key' is prefixed with an identifier if it corresponds to a cached POST. + // Skip past that to locate the actual URL. + // + // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an + // URL corresponding to a registered MockTransaction. It would be good to + // have another way to access the test_mode. + GURL url; + if (isdigit(key[0])) { + size_t slash = key.find('/'); + DCHECK(slash != std::string::npos); + url = GURL(key.substr(slash + 1)); + } else { + url = GURL(key); + } + const MockTransaction* t = FindMockTransaction(url); + DCHECK(t); + return t->test_mode; +} + //----------------------------------------------------------------------------- // mock disk cache (a very basic memory cache implementation) @@ -41,25 +61,7 @@ class MockDiskEntry : public disk_cache::Entry, explicit MockDiskEntry(const std::string& key) : key_(key), doomed_(false), sparse_(false), fail_requests_(false), busy_(false), delayed_(false) { - // - // 'key' is prefixed with an identifier if it corresponds to a cached POST. - // Skip past that to locate the actual URL. - // - // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an - // URL corresponding to a registered MockTransaction. It would be good to - // have another way to access the test_mode. - // - GURL url; - if (isdigit(key[0])) { - size_t slash = key.find('/'); - DCHECK(slash != std::string::npos); - url = GURL(key.substr(slash + 1)); - } else { - url = GURL(key); - } - const MockTransaction* t = FindMockTransaction(url); - DCHECK(t); - test_mode_ = t->test_mode; + test_mode_ = GetTestModeForEntry(key); } bool is_doomed() const { return doomed_; } @@ -353,17 +355,23 @@ class MockDiskCache : public disk_cache::Backend { } virtual bool OpenEntry(const std::string& key, disk_cache::Entry** entry) { + NOTREACHED(); + return false; + } + + virtual int OpenEntry(const std::string& key, disk_cache::Entry** entry, + net::CompletionCallback* callback) { if (fail_requests_) - return false; + return net::ERR_CACHE_OPEN_FAILURE; EntryMap::iterator it = entries_.find(key); if (it == entries_.end()) - return false; + return net::ERR_CACHE_OPEN_FAILURE; if (it->second->is_doomed()) { it->second->Release(); entries_.erase(it); - return false; + return net::ERR_CACHE_OPEN_FAILURE; } open_count_++; @@ -374,20 +382,29 @@ class MockDiskCache : public disk_cache::Backend { if (soft_failures_) it->second->set_fail_requests(); - return true; - } + if (!callback || (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START)) + return net::OK; - virtual int OpenEntry(const std::string& key, disk_cache::Entry** entry, - net::CompletionCallback* callback) { - return net::ERR_NOT_IMPLEMENTED; + CallbackLater(callback, net::OK); + return net::ERR_IO_PENDING; } virtual bool CreateEntry(const std::string& key, disk_cache::Entry** entry) { + NOTREACHED(); + return false; + } + + virtual int CreateEntry(const std::string& key, disk_cache::Entry** entry, + net::CompletionCallback* callback) { if (fail_requests_) - return false; + return net::ERR_CACHE_CREATE_FAILURE; EntryMap::iterator it = entries_.find(key); - DCHECK(it == entries_.end()); + if (it != entries_.end()) { + DCHECK(it->second->is_doomed()); + it->second->Release(); + entries_.erase(it); + } create_count_++; @@ -402,21 +419,30 @@ class MockDiskCache : public disk_cache::Backend { if (soft_failures_) new_entry->set_fail_requests(); - return true; - } + if (!callback || (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START)) + return net::OK; - virtual int CreateEntry(const std::string& key, disk_cache::Entry** entry, - net::CompletionCallback* callback) { - return net::ERR_NOT_IMPLEMENTED; + CallbackLater(callback, net::OK); + return net::ERR_IO_PENDING; } virtual bool DoomEntry(const std::string& key) { + return false; + } + + virtual int DoomEntry(const std::string& key, + net::CompletionCallback* callback) { EntryMap::iterator it = entries_.find(key); if (it != entries_.end()) { it->second->Release(); entries_.erase(it); } - return true; + + if (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START) + return net::OK; + + CallbackLater(callback, net::OK); + return net::ERR_IO_PENDING; } virtual bool DoomAllEntries() { @@ -429,7 +455,7 @@ class MockDiskCache : public disk_cache::Backend { virtual bool DoomEntriesBetween(const Time initial_time, const Time end_time) { - return true; + return false; } virtual int DoomEntriesBetween(const base::Time initial_time, @@ -439,7 +465,7 @@ class MockDiskCache : public disk_cache::Backend { } virtual bool DoomEntriesSince(const Time initial_time) { - return true; + return false; } virtual int DoomEntriesSince(const base::Time initial_time, @@ -476,6 +502,26 @@ class MockDiskCache : public disk_cache::Backend { private: typedef base::hash_map<std::string, MockDiskEntry*> EntryMap; + + class CallbackRunner : public Task { + public: + CallbackRunner(net::CompletionCallback* callback, int result) + : callback_(callback), result_(result) {} + virtual void Run() { + callback_->Run(result_); + } + + private: + net::CompletionCallback* callback_; + int result_; + DISALLOW_COPY_AND_ASSIGN(CallbackRunner); + }; + + void CallbackLater(net::CompletionCallback* callback, int result) { + MessageLoop::current()->PostTask(FROM_HERE, + new CallbackRunner(callback, result)); + } + EntryMap entries_; int open_count_; int create_count_; @@ -913,7 +959,8 @@ TEST(HttpCache, SimpleGETWithDiskFailures2) { // We have to open the entry again to propagate the failure flag. disk_cache::Entry* en; - ASSERT_TRUE(cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url, &en)); + ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url, + &en, NULL)); en->Close(); ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); @@ -1198,7 +1245,10 @@ TEST(HttpCache, SimpleGET_ManyReaders) { c->result = c->trans->Start(&request, &c->callback, NULL); } - // the first request should be a writer at this point, and the subsequent + // Allow all requests to move from the Create queue to the active entry. + MessageLoop::current()->RunAllPending(); + + // The first request should be a writer at this point, and the subsequent // requests should be pending. EXPECT_EQ(1, cache.network_layer()->transaction_count()); @@ -1212,7 +1262,7 @@ TEST(HttpCache, SimpleGET_ManyReaders) { ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); } - // we should not have had to re-open the disk entry + // We should not have had to re-open the disk entry EXPECT_EQ(1, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); @@ -1252,6 +1302,9 @@ TEST(HttpCache, SimpleGET_RacingReaders) { c->result = c->trans->Start(this_request, &c->callback, NULL); } + // Allow all requests to move from the Create queue to the active entry. + MessageLoop::current()->RunAllPending(); + // The first request should be a writer at this point, and the subsequent // requests should be pending. @@ -1373,6 +1426,9 @@ TEST(HttpCache, FastNoStoreGET_DoneWithPending) { c->result = c->trans->Start(&request, &c->callback, NULL); } + // Allow all requests to move from the Create queue to the active entry. + MessageLoop::current()->RunAllPending(); + // The first request should be a writer at this point, and the subsequent // requests should be pending. @@ -1416,7 +1472,10 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) { c->result = c->trans->Start(&request, &c->callback, NULL); } - // the first request should be a writer at this point, and the subsequent + // Allow all requests to move from the Create queue to the active entry. + MessageLoop::current()->RunAllPending(); + + // The first request should be a writer at this point, and the subsequent // requests should be pending. EXPECT_EQ(1, cache.network_layer()->transaction_count()); @@ -1427,20 +1486,20 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) { Context* c = context_list[i]; if (c->result == net::ERR_IO_PENDING) c->result = c->callback.WaitForResult(); - // destroy only the first transaction + // Destroy only the first transaction. if (i == 0) { delete c; context_list[i] = NULL; } } - // complete the rest of the transactions + // Complete the rest of the transactions. for (int i = 1; i < kNumTransactions; ++i) { Context* c = context_list[i]; ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); } - // we should have had to re-open the disk entry + // We should have had to re-open the disk entry. EXPECT_EQ(2, cache.network_layer()->transaction_count()); EXPECT_EQ(0, cache.disk_cache()->open_count()); @@ -1452,6 +1511,107 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) { } } +// Tests that we can cancel requests that are queued waiting to open the disk +// cache entry. +TEST(HttpCache, SimpleGET_ManyWriters_CancelCreate) { + MockHttpCache cache; + + MockHttpRequest request(kSimpleGET_Transaction); + + std::vector<Context*> context_list; + const int kNumTransactions = 5; + + for (int i = 0; i < kNumTransactions; i++) { + context_list.push_back(new Context()); + Context* c = context_list[i]; + + c->result = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(net::OK, c->result); + + c->result = c->trans->Start(&request, &c->callback, NULL); + } + + // The first request should be creating the disk cache entry and the others + // should be pending. + + EXPECT_EQ(0, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Cancel a request from the pending queue. + delete context_list[3]; + context_list[3] = NULL; + + // Cancel the request that is creating the entry. This will force the pending + // operations to restart. + delete context_list[0]; + context_list[0] = NULL; + + // Complete the rest of the transactions. + for (int i = 1; i < kNumTransactions; i++) { + Context* c = context_list[i]; + if (c) { + c->result = c->callback.GetResult(c->result); + ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); + } + } + + // We should have had to re-create the disk entry. + + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(2, cache.disk_cache()->create_count()); + + for (int i = 1; i < kNumTransactions; ++i) { + delete context_list[i]; + } +} + +// Tests that we delete/create entries even if multiple requests are queued. +TEST(HttpCache, SimpleGET_ManyWriters_BypassCache) { + MockHttpCache cache; + + MockHttpRequest request(kSimpleGET_Transaction); + request.load_flags = net::LOAD_BYPASS_CACHE; + + std::vector<Context*> context_list; + const int kNumTransactions = 5; + + for (int i = 0; i < kNumTransactions; i++) { + context_list.push_back(new Context()); + Context* c = context_list[i]; + + c->result = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(net::OK, c->result); + + c->result = c->trans->Start(&request, &c->callback, NULL); + } + + // The first request should be deleting the disk cache entry and the others + // should be pending. + + EXPECT_EQ(0, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(0, cache.disk_cache()->create_count()); + + // Complete the transactions. + for (int i = 0; i < kNumTransactions; i++) { + Context* c = context_list[i]; + c->result = c->callback.GetResult(c->result); + ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction); + } + + // We should have had to re-create the disk entry multiple times. + + EXPECT_EQ(5, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(5, cache.disk_cache()->create_count()); + + for (int i = 0; i < kNumTransactions; ++i) { + delete context_list[i]; + } +} + TEST(HttpCache, SimpleGET_AbandonedCacheRead) { MockHttpCache cache; @@ -2626,8 +2786,8 @@ TEST(HttpCache, GET_Previous206_NotSparse) { // Create a disk cache entry that stores 206 headers while not being sparse. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry(kSimpleGET_Transaction.url, - &entry)); + ASSERT_EQ(net::OK, cache.disk_cache()->CreateEntry(kSimpleGET_Transaction.url, + &entry, NULL)); std::string raw_headers(kRangeGET_TransactionOK.status); raw_headers.append("\n"); @@ -2669,8 +2829,9 @@ TEST(HttpCache, RangeGET_Previous206_NotSparse_2) { // Create a disk cache entry that stores 206 headers while not being sparse. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_EQ(net::OK, + cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, + &entry, NULL)); std::string raw_headers(kRangeGET_TransactionOK.status); raw_headers.append("\n"); @@ -2858,8 +3019,8 @@ TEST(HttpCache, RangeGET_Cancel) { // Verify that the entry has not been deleted. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, + &entry, NULL)); entry->Close(); RemoveMockTransaction(&kRangeGET_TransactionOK); } @@ -2992,8 +3153,9 @@ TEST(HttpCache, RangeGET_InvalidResponse1) { EXPECT_EQ(1, cache.disk_cache()->create_count()); // Verify that we don't have a cached entry. - disk_cache::Entry* en; - ASSERT_FALSE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, &en)); + disk_cache::Entry* entry; + EXPECT_NE(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, + &entry, NULL)); RemoveMockTransaction(&kRangeGET_TransactionOK); } @@ -3021,8 +3183,9 @@ TEST(HttpCache, RangeGET_InvalidResponse2) { EXPECT_EQ(1, cache.disk_cache()->create_count()); // Verify that we don't have a cached entry. - disk_cache::Entry* en; - ASSERT_FALSE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, &en)); + disk_cache::Entry* entry; + EXPECT_NE(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, + &entry, NULL)); RemoveMockTransaction(&kRangeGET_TransactionOK); } @@ -3063,7 +3226,8 @@ TEST(HttpCache, RangeGET_InvalidResponse3) { // Verify that we cached the first response but not the second one. disk_cache::Entry* en; - ASSERT_TRUE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, &en)); + ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, + &en, NULL)); int64 cached_start = 0; EXPECT_EQ(10, en->GetAvailableRange(40, 20, &cached_start)); EXPECT_EQ(50, cached_start); @@ -3211,7 +3375,8 @@ TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) { TEST(HttpCache, WriteResponseInfo_Truncated) { MockHttpCache cache; disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry("http://www.google.com", &entry)); + ASSERT_EQ(net::OK, cache.disk_cache()->CreateEntry("http://www.google.com", + &entry, NULL)); std::string headers("HTTP/1.1 200 OK"); headers = net::HttpUtil::AssembleRawHeaders(headers.data(), headers.size()); @@ -3383,8 +3548,8 @@ TEST(HttpCache, Set_Truncated_Flag) { // Verify that the entry is marked as incomplete. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url, - &entry)); + ASSERT_EQ(net::OK, cache.disk_cache()->OpenEntry(kSimpleGET_Transaction.url, + &entry, NULL)); net::HttpResponseInfo response; bool truncated = false; EXPECT_TRUE(net::HttpCache::ReadResponseInfo(entry, &response, &truncated)); @@ -3402,8 +3567,9 @@ TEST(HttpCache, GET_IncompleteResource) { // Create a disk cache entry that stores an incomplete resource. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_EQ(net::OK, + cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry, + NULL)); std::string raw_headers("HTTP/1.1 200 OK\n" "Last-Modified: Sat, 18 Apr 2009 01:10:43 GMT\n" @@ -3462,8 +3628,10 @@ TEST(HttpCache, GET_IncompleteResource2) { // Create a disk cache entry that stores an incomplete resource. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_EQ(net::OK, + cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry, + NULL)); + // Content-length will be intentionally bad. std::string raw_headers("HTTP/1.1 200 OK\n" @@ -3508,8 +3676,8 @@ TEST(HttpCache, GET_IncompleteResource2) { RemoveMockTransaction(&kRangeGET_TransactionOK); // Verify that the disk entry was deleted. - EXPECT_FALSE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_NE(net::OK, cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, + &entry, NULL)); } // Tests that when we cancel a request that was interrupted, we mark it again @@ -3521,8 +3689,9 @@ TEST(HttpCache, GET_CancelIncompleteResource) { // Create a disk cache entry that stores an incomplete resource. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_EQ(net::OK, + cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry, + NULL)); std::string raw_headers("HTTP/1.1 200 OK\n" "Last-Modified: Sat, 18 Apr 2009 01:10:43 GMT\n" @@ -3586,8 +3755,9 @@ TEST(HttpCache, RangeGET_IncompleteResource) { // Create a disk cache entry that stores an incomplete resource. disk_cache::Entry* entry; - ASSERT_TRUE(cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, - &entry)); + ASSERT_EQ(net::OK, + cache.disk_cache()->CreateEntry(kRangeGET_TransactionOK.url, &entry, + NULL)); // Content-length will be intentionally bogus. std::string raw_headers("HTTP/1.1 200 OK\n" @@ -3766,8 +3936,8 @@ TEST(HttpCache, CacheControlNoStore) { EXPECT_EQ(2, cache.disk_cache()->create_count()); disk_cache::Entry* entry; - bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry); - EXPECT_FALSE(exists); + EXPECT_NE(net::OK, + cache.disk_cache()->OpenEntry(transaction.url, &entry, NULL)); } TEST(HttpCache, CacheControlNoStore2) { @@ -3795,8 +3965,8 @@ TEST(HttpCache, CacheControlNoStore2) { EXPECT_EQ(1, cache.disk_cache()->create_count()); disk_cache::Entry* entry; - bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry); - EXPECT_FALSE(exists); + EXPECT_NE(net::OK, + cache.disk_cache()->OpenEntry(transaction.url, &entry, NULL)); } TEST(HttpCache, CacheControlNoStore3) { @@ -3825,8 +3995,8 @@ TEST(HttpCache, CacheControlNoStore3) { EXPECT_EQ(1, cache.disk_cache()->create_count()); disk_cache::Entry* entry; - bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry); - EXPECT_FALSE(exists); + EXPECT_NE(net::OK, + cache.disk_cache()->OpenEntry(transaction.url, &entry, NULL)); } // Ensure that we don't cache requests served over bad HTTPS. |