| Index: net/http/http_cache_transaction.cc
|
| ===================================================================
|
| --- net/http/http_cache_transaction.cc (revision 31582)
|
| +++ net/http/http_cache_transaction.cc (working copy)
|
| @@ -2,19 +2,14 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "net/http/http_cache.h"
|
| +#include "net/http/http_cache_transaction.h"
|
|
|
| -#include <algorithm>
|
| -#include <string>
|
| -
|
| #include "base/compiler_specific.h"
|
|
|
| #if defined(OS_POSIX)
|
| #include <unistd.h>
|
| #endif
|
|
|
| -#include "base/message_loop.h"
|
| -#include "base/pickle.h"
|
| #include "base/ref_counted.h"
|
| #include "base/string_util.h"
|
| #include "base/time.h"
|
| @@ -24,11 +19,8 @@
|
| #include "net/base/net_errors.h"
|
| #include "net/base/ssl_cert_request_info.h"
|
| #include "net/disk_cache/disk_cache.h"
|
| -#include "net/http/http_network_layer.h"
|
| -#include "net/http/http_network_session.h"
|
| #include "net/http/http_request_info.h"
|
| #include "net/http/http_response_headers.h"
|
| -#include "net/http/http_response_info.h"
|
| #include "net/http/http_transaction.h"
|
| #include "net/http/http_util.h"
|
| #include "net/http/partial_data.h"
|
| @@ -69,15 +61,6 @@
|
| { "if-none-match", "etag" },
|
| };
|
|
|
| -// Helper struct to pair a header name with its value, for
|
| -// headers used to validate cache entries.
|
| -struct ValidationHeaders {
|
| - ValidationHeaders() : initialized(false) {}
|
| -
|
| - std::string values[ARRAYSIZE_UNSAFE(kValidationHeaders)];
|
| - bool initialized;
|
| -};
|
| -
|
| // If the request includes one of these request headers, then avoid reusing
|
| // our cached copy if any.
|
| static const HeaderNameAndValue kForceFetchHeaders[] = {
|
| @@ -113,282 +96,38 @@
|
|
|
| //-----------------------------------------------------------------------------
|
|
|
| -HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* e)
|
| - : disk_entry(e),
|
| - writer(NULL),
|
| - will_process_pending_queue(false),
|
| - doomed(false) {
|
| +HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support)
|
| + : request_(NULL),
|
| + cache_(cache->AsWeakPtr()),
|
| + entry_(NULL),
|
| + network_trans_(NULL),
|
| + callback_(NULL),
|
| + mode_(NONE),
|
| + reading_(false),
|
| + invalid_range_(false),
|
| + enable_range_support_(enable_range_support),
|
| + truncated_(false),
|
| + read_offset_(0),
|
| + effective_load_flags_(0),
|
| + final_upload_progress_(0),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + cache_read_callback_(new CancelableCompletionCallback<Transaction>(
|
| + this, &Transaction::OnCacheReadCompleted))),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + cache_write_callback_(new CancelableCompletionCallback<Transaction>(
|
| + this, &Transaction::OnCacheWriteCompleted))),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(
|
| + entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
|
| + this, &Transaction::OnCacheEntryReady))) {
|
| + COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
|
| + ARRAYSIZE_UNSAFE(kValidationHeaders),
|
| + Invalid_number_of_validation_headers);
|
| }
|
|
|
| -HttpCache::ActiveEntry::~ActiveEntry() {
|
| - if (disk_entry)
|
| - disk_entry->Close();
|
| -}
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -class HttpCache::Transaction : public HttpTransaction {
|
| - public:
|
| - Transaction(HttpCache* cache, bool enable_range_support)
|
| - : request_(NULL),
|
| - cache_(cache->AsWeakPtr()),
|
| - entry_(NULL),
|
| - network_trans_(NULL),
|
| - callback_(NULL),
|
| - mode_(NONE),
|
| - reading_(false),
|
| - invalid_range_(false),
|
| - enable_range_support_(enable_range_support),
|
| - truncated_(false),
|
| - read_offset_(0),
|
| - effective_load_flags_(0),
|
| - final_upload_progress_(0),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(
|
| - network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(
|
| - network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(
|
| - cache_read_callback_(new CancelableCompletionCallback<Transaction>(
|
| - this, &Transaction::OnCacheReadCompleted))),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(
|
| - cache_write_callback_(new CancelableCompletionCallback<Transaction>(
|
| - this, &Transaction::OnCacheWriteCompleted))),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(
|
| - entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
|
| - this, &Transaction::OnCacheEntryReady))) {
|
| - }
|
| -
|
| - // Clean up the transaction.
|
| - virtual ~Transaction();
|
| -
|
| - // HttpTransaction methods:
|
| - virtual int Start(const HttpRequestInfo*, CompletionCallback*, LoadLog*);
|
| - virtual int RestartIgnoringLastError(CompletionCallback*);
|
| - virtual int RestartWithCertificate(X509Certificate* client_cert,
|
| - CompletionCallback* callback);
|
| - virtual int RestartWithAuth(const std::wstring& username,
|
| - const std::wstring& password,
|
| - CompletionCallback* callback);
|
| - virtual bool IsReadyToRestartForAuth();
|
| - virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback*);
|
| - virtual const HttpResponseInfo* GetResponseInfo() const;
|
| - virtual LoadState GetLoadState() const;
|
| - virtual uint64 GetUploadProgress(void) const;
|
| -
|
| - // The transaction has the following modes, which apply to how it may access
|
| - // its cache entry.
|
| - //
|
| - // o If the mode of the transaction is NONE, then it is in "pass through"
|
| - // mode and all methods just forward to the inner network transaction.
|
| - //
|
| - // o If the mode of the transaction is only READ, then it may only read from
|
| - // the cache entry.
|
| - //
|
| - // o If the mode of the transaction is only WRITE, then it may only write to
|
| - // the cache entry.
|
| - //
|
| - // o If the mode of the transaction is READ_WRITE, then the transaction may
|
| - // optionally modify the cache entry (e.g., possibly corresponding to
|
| - // cache validation).
|
| - //
|
| - // o If the mode of the transaction is UPDATE, then the transaction may
|
| - // update existing cache entries, but will never create a new entry or
|
| - // respond using the entry read from the cache.
|
| - enum Mode {
|
| - NONE = 0,
|
| - READ_META = 1 << 0,
|
| - READ_DATA = 1 << 1,
|
| - READ = READ_META | READ_DATA,
|
| - WRITE = 1 << 2,
|
| - READ_WRITE = READ | WRITE,
|
| - UPDATE = READ_META | WRITE, // READ_WRITE & ~READ_DATA
|
| - };
|
| -
|
| - Mode mode() const { return mode_; }
|
| -
|
| - const std::string& key() const { return cache_key_; }
|
| -
|
| - // Associates this transaction with a cache entry.
|
| - int AddToEntry();
|
| -
|
| - // Called by the HttpCache when the given disk cache entry becomes accessible
|
| - // to the transaction. Returns network error code.
|
| - int EntryAvailable(ActiveEntry* entry);
|
| -
|
| - // This transaction is being deleted and we are not done writing to the cache.
|
| - // We need to indicate that the response data was truncated. Returns true on
|
| - // success.
|
| - bool AddTruncatedFlag();
|
| -
|
| - private:
|
| - // This is a helper function used to trigger a completion callback. It may
|
| - // only be called if callback_ is non-null.
|
| - void DoCallback(int rv);
|
| -
|
| - // This will trigger the completion callback if appropriate.
|
| - int HandleResult(int rv);
|
| -
|
| - // Sets request_ and fields derived from it.
|
| - void SetRequest(LoadLog* load_log, const HttpRequestInfo* request);
|
| -
|
| - // Returns true if the request should be handled exclusively by the network
|
| - // layer (skipping the cache entirely).
|
| - bool ShouldPassThrough();
|
| -
|
| - // Called to begin reading from the cache. Returns network error code.
|
| - int BeginCacheRead();
|
| -
|
| - // Called to begin validating the cache entry. Returns network error code.
|
| - int BeginCacheValidation();
|
| -
|
| - // Called to begin validating an entry that stores partial content. Returns
|
| - // a network error code.
|
| - int BeginPartialCacheValidation();
|
| -
|
| - // Validates the entry headers against the requested range and continues with
|
| - // the validation of the rest of the entry. Returns a network error code.
|
| - int ValidateEntryHeadersAndContinue(bool byte_range_requested);
|
| -
|
| - // Performs the cache validation for the next chunk of data stored by the
|
| - // cache. If this chunk is not currently stored, starts the network request
|
| - // to fetch it. Returns a network error code.
|
| - int ContinuePartialCacheValidation();
|
| -
|
| - // Called to start requests which were given an "if-modified-since" or
|
| - // "if-none-match" validation header by the caller (NOT when the request was
|
| - // conditionalized internally in response to LOAD_VALIDATE_CACHE).
|
| - // Returns a network error code.
|
| - int BeginExternallyConditionalizedRequest();
|
| -
|
| - // Called to begin a network transaction. Returns network error code.
|
| - int BeginNetworkRequest();
|
| -
|
| - // Called to restart a network transaction after an error. Returns network
|
| - // error code.
|
| - int RestartNetworkRequest();
|
| -
|
| - // Called to restart a network transaction with a client certificate.
|
| - // Returns network error code.
|
| - int RestartNetworkRequestWithCertificate(X509Certificate* client_cert);
|
| -
|
| - // Called to restart a network transaction with authentication credentials.
|
| - // Returns network error code.
|
| - int RestartNetworkRequestWithAuth(const std::wstring& username,
|
| - const std::wstring& password);
|
| -
|
| - // Called to determine if we need to validate the cache entry before using it.
|
| - bool RequiresValidation();
|
| -
|
| - // Called to make the request conditional (to ask the server if the cached
|
| - // copy is valid). Returns true if able to make the request conditional.
|
| - bool ConditionalizeRequest();
|
| -
|
| - // Makes sure that a 206 response is expected. Returns a network error code.
|
| - bool ValidatePartialResponse(const HttpResponseHeaders* headers);
|
| -
|
| - // Handles a response validation error by bypassing the cache.
|
| - void IgnoreRangeRequest();
|
| -
|
| - // Reads data from the network.
|
| - int ReadFromNetwork(IOBuffer* data, int data_len);
|
| -
|
| - // Reads data from the cache entry.
|
| - int ReadFromEntry(IOBuffer* data, int data_len);
|
| -
|
| - // Called to populate response_ from the cache entry.
|
| - int ReadResponseInfoFromEntry();
|
| -
|
| - // Called to write data to the cache entry. If the write fails, then the
|
| - // cache entry is destroyed. Future calls to this function will just do
|
| - // nothing without side-effect. Returns a network error code.
|
| - int WriteToEntry(int index, int offset, IOBuffer* data, int data_len,
|
| - CompletionCallback* callback);
|
| -
|
| - // Called to write response_ to the cache entry. |truncated| indicates if the
|
| - // entry should be marked as incomplete.
|
| - void WriteResponseInfoToEntry(bool truncated);
|
| -
|
| - // Called to append response data to the cache entry. Returns a network error
|
| - // code.
|
| - int AppendResponseDataToEntry(IOBuffer* data, int data_len,
|
| - CompletionCallback* callback);
|
| -
|
| - // Called to truncate response content in the entry.
|
| - void TruncateResponseData();
|
| -
|
| - // Called when we are done writing to the cache entry.
|
| - void DoneWritingToEntry(bool success);
|
| -
|
| - // Deletes the current partial cache entry (sparse), and optionally removes
|
| - // the control object (partial_).
|
| - void DoomPartialEntry(bool delete_object);
|
| -
|
| - // Performs the needed work after receiving data from the network.
|
| - int DoNetworkReadCompleted(int result);
|
| -
|
| - // Performs the needed work after receiving data from the network, when
|
| - // working with range requests.
|
| - int DoPartialNetworkReadCompleted(int result);
|
| -
|
| - // Performs the needed work after receiving data from the cache.
|
| - int DoCacheReadCompleted(int result);
|
| -
|
| - // Performs the needed work after receiving data from the cache, when
|
| - // working with range requests.
|
| - int DoPartialCacheReadCompleted(int result);
|
| -
|
| - // Performs the needed work after writing data to the cache.
|
| - int DoCacheWriteCompleted(int result);
|
| -
|
| - // Called to signal completion of the network transaction's Start method:
|
| - void OnNetworkInfoAvailable(int result);
|
| -
|
| - // Called to signal completion of the network transaction's Read method:
|
| - void OnNetworkReadCompleted(int result);
|
| -
|
| - // Called to signal completion of the cache's ReadData method:
|
| - void OnCacheReadCompleted(int result);
|
| -
|
| - // Called to signal completion of the cache's WriteData method:
|
| - void OnCacheWriteCompleted(int result);
|
| -
|
| - // Called to signal completion of the cache entry's ReadyForSparseIO method:
|
| - void OnCacheEntryReady(int result);
|
| -
|
| - scoped_refptr<LoadLog> load_log_;
|
| - const HttpRequestInfo* request_;
|
| - scoped_ptr<HttpRequestInfo> custom_request_;
|
| - // If extra_headers specified a "if-modified-since" or "if-none-match",
|
| - // |external_validation_| contains the value of those headers.
|
| - ValidationHeaders external_validation_;
|
| - base::WeakPtr<HttpCache> cache_;
|
| - HttpCache::ActiveEntry* entry_;
|
| - scoped_ptr<HttpTransaction> network_trans_;
|
| - CompletionCallback* callback_; // Consumer's callback.
|
| - HttpResponseInfo response_;
|
| - HttpResponseInfo auth_response_;
|
| - std::string cache_key_;
|
| - Mode mode_;
|
| - bool reading_; // We are already reading.
|
| - bool invalid_range_; // We may bypass the cache for this request.
|
| - bool enable_range_support_;
|
| - bool truncated_; // We don't have all the response data.
|
| - scoped_refptr<IOBuffer> read_buf_;
|
| - int read_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_info_callback_;
|
| - CompletionCallbackImpl<Transaction> network_read_callback_;
|
| - scoped_refptr<CancelableCompletionCallback<Transaction> >
|
| - cache_read_callback_;
|
| - scoped_refptr<CancelableCompletionCallback<Transaction> >
|
| - cache_write_callback_;
|
| - scoped_refptr<CancelableCompletionCallback<Transaction> >
|
| - entry_ready_callback_;
|
| -};
|
| -
|
| HttpCache::Transaction::~Transaction() {
|
| if (cache_) {
|
| if (entry_) {
|
| @@ -1629,487 +1368,4 @@
|
| ValidateEntryHeadersAndContinue(true);
|
| }
|
|
|
| -//-----------------------------------------------------------------------------
|
| -
|
| -HttpCache::HttpCache(HostResolver* host_resolver,
|
| - ProxyService* proxy_service,
|
| - SSLConfigService* ssl_config_service,
|
| - const FilePath& cache_dir,
|
| - int cache_size)
|
| - : disk_cache_dir_(cache_dir),
|
| - mode_(NORMAL),
|
| - type_(DISK_CACHE),
|
| - network_layer_(HttpNetworkLayer::CreateFactory(
|
| - host_resolver, proxy_service, ssl_config_service)),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| - enable_range_support_(true),
|
| - cache_size_(cache_size) {
|
| -}
|
| -
|
| -HttpCache::HttpCache(HttpNetworkSession* session,
|
| - const FilePath& cache_dir,
|
| - int cache_size)
|
| - : disk_cache_dir_(cache_dir),
|
| - mode_(NORMAL),
|
| - type_(DISK_CACHE),
|
| - network_layer_(HttpNetworkLayer::CreateFactory(session)),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| - enable_range_support_(true),
|
| - cache_size_(cache_size) {
|
| -}
|
| -
|
| -HttpCache::HttpCache(HostResolver* host_resolver,
|
| - ProxyService* proxy_service,
|
| - SSLConfigService* ssl_config_service,
|
| - int cache_size)
|
| - : mode_(NORMAL),
|
| - type_(MEMORY_CACHE),
|
| - network_layer_(HttpNetworkLayer::CreateFactory(
|
| - host_resolver, proxy_service, ssl_config_service)),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| - enable_range_support_(true),
|
| - cache_size_(cache_size) {
|
| -}
|
| -
|
| -HttpCache::HttpCache(HttpTransactionFactory* network_layer,
|
| - disk_cache::Backend* disk_cache)
|
| - : mode_(NORMAL),
|
| - type_(DISK_CACHE),
|
| - network_layer_(network_layer),
|
| - disk_cache_(disk_cache),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
|
| - enable_range_support_(true),
|
| - cache_size_(0) {
|
| -}
|
| -
|
| -HttpCache::~HttpCache() {
|
| - // If we have any active entries remaining, then we need to deactivate them.
|
| - // We may have some pending calls to OnProcessPendingQueue, but since those
|
| - // won't run (due to our destruction), we can simply ignore the corresponding
|
| - // will_process_pending_queue flag.
|
| - while (!active_entries_.empty()) {
|
| - ActiveEntry* entry = active_entries_.begin()->second;
|
| - entry->will_process_pending_queue = false;
|
| - entry->pending_queue.clear();
|
| - entry->readers.clear();
|
| - entry->writer = NULL;
|
| - DeactivateEntry(entry);
|
| - }
|
| -
|
| - ActiveEntriesSet::iterator it = doomed_entries_.begin();
|
| - for (; it != doomed_entries_.end(); ++it)
|
| - delete *it;
|
| -}
|
| -
|
| -disk_cache::Backend* HttpCache::GetBackend() {
|
| - if (disk_cache_.get())
|
| - return disk_cache_.get();
|
| -
|
| - DCHECK_GE(cache_size_, 0);
|
| - if (type_ == MEMORY_CACHE) {
|
| - // We may end up with no folder name and no cache if the initialization
|
| - // of the disk cache fails. We want to be sure that what we wanted to have
|
| - // was an in-memory cache.
|
| - disk_cache_.reset(disk_cache::CreateInMemoryCacheBackend(cache_size_));
|
| - } else if (!disk_cache_dir_.empty()) {
|
| - disk_cache_.reset(disk_cache::CreateCacheBackend(disk_cache_dir_, true,
|
| - cache_size_, type_));
|
| - disk_cache_dir_ = FilePath(); // Reclaim memory.
|
| - }
|
| - return disk_cache_.get();
|
| -}
|
| -
|
| -int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
|
| - // Do lazy initialization of disk cache if needed.
|
| - GetBackend();
|
| - trans->reset(new HttpCache::Transaction(this, enable_range_support_));
|
| - return OK;
|
| -}
|
| -
|
| -HttpCache* HttpCache::GetCache() {
|
| - return this;
|
| -}
|
| -
|
| -HttpNetworkSession* HttpCache::GetSession() {
|
| - net::HttpNetworkLayer* network =
|
| - static_cast<net::HttpNetworkLayer*>(network_layer_.get());
|
| - return network->GetSession();
|
| -}
|
| -
|
| -void HttpCache::Suspend(bool suspend) {
|
| - network_layer_->Suspend(suspend);
|
| -}
|
| -
|
| -// static
|
| -bool HttpCache::ParseResponseInfo(const char* data, int len,
|
| - HttpResponseInfo* response_info,
|
| - bool* response_truncated) {
|
| - Pickle pickle(data, len);
|
| - return response_info->InitFromPickle(pickle, response_truncated);
|
| -}
|
| -
|
| -// static
|
| -bool HttpCache::ReadResponseInfo(disk_cache::Entry* disk_entry,
|
| - HttpResponseInfo* response_info,
|
| - bool* response_truncated) {
|
| - int size = disk_entry->GetDataSize(kResponseInfoIndex);
|
| -
|
| - scoped_refptr<IOBuffer> buffer = new IOBuffer(size);
|
| - int rv = disk_entry->ReadData(kResponseInfoIndex, 0, buffer, size, NULL);
|
| - if (rv != size) {
|
| - DLOG(ERROR) << "ReadData failed: " << rv;
|
| - return false;
|
| - }
|
| -
|
| - return ParseResponseInfo(buffer->data(), size, response_info,
|
| - response_truncated);
|
| -}
|
| -
|
| -// static
|
| -bool HttpCache::WriteResponseInfo(disk_cache::Entry* disk_entry,
|
| - const HttpResponseInfo* response_info,
|
| - bool skip_transient_headers,
|
| - bool response_truncated) {
|
| - Pickle pickle;
|
| - response_info->Persist(
|
| - &pickle, skip_transient_headers, response_truncated);
|
| -
|
| - scoped_refptr<WrappedIOBuffer> data = new WrappedIOBuffer(
|
| - reinterpret_cast<const char*>(pickle.data()));
|
| - int len = static_cast<int>(pickle.size());
|
| -
|
| - return disk_entry->WriteData(kResponseInfoIndex, 0, data, len, NULL,
|
| - true) == len;
|
| -}
|
| -
|
| -// Generate a key that can be used inside the cache.
|
| -std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
|
| - // Strip out the reference, username, and password sections of the URL.
|
| - std::string url = HttpUtil::SpecForRequest(request->url);
|
| -
|
| - DCHECK(mode_ != DISABLE);
|
| - if (mode_ == NORMAL) {
|
| - // No valid URL can begin with numerals, so we should not have to worry
|
| - // about collisions with normal URLs.
|
| - if (request->upload_data && request->upload_data->identifier())
|
| - url.insert(0, StringPrintf("%lld/", request->upload_data->identifier()));
|
| - return url;
|
| - }
|
| -
|
| - // In playback and record mode, we cache everything.
|
| -
|
| - // Lazily initialize.
|
| - if (playback_cache_map_ == NULL)
|
| - playback_cache_map_.reset(new PlaybackCacheMap());
|
| -
|
| - // Each time we request an item from the cache, we tag it with a
|
| - // generation number. During playback, multiple fetches for the same
|
| - // item will use the same generation number and pull the proper
|
| - // instance of an URL from the cache.
|
| - int generation = 0;
|
| - DCHECK(playback_cache_map_ != NULL);
|
| - if (playback_cache_map_->find(url) != playback_cache_map_->end())
|
| - generation = (*playback_cache_map_)[url];
|
| - (*playback_cache_map_)[url] = generation + 1;
|
| -
|
| - // The key into the cache is GENERATION # + METHOD + URL.
|
| - std::string result = IntToString(generation);
|
| - result.append(request->method);
|
| - result.append(url);
|
| - return result;
|
| -}
|
| -
|
| -void HttpCache::DoomEntry(const std::string& key) {
|
| - // 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);
|
| -
|
| - // 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);
|
| -
|
| - entry->disk_entry->Doom();
|
| - entry->doomed = true;
|
| -
|
| - DCHECK(entry->writer || !entry->readers.empty());
|
| - }
|
| -}
|
| -
|
| -void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) {
|
| - DCHECK(entry->doomed);
|
| - DCHECK(!entry->writer);
|
| - DCHECK(entry->readers.empty());
|
| - DCHECK(entry->pending_queue.empty());
|
| -
|
| - ActiveEntriesSet::iterator it = doomed_entries_.find(entry);
|
| - DCHECK(it != doomed_entries_.end());
|
| - doomed_entries_.erase(it);
|
| -
|
| - delete entry;
|
| -}
|
| -
|
| -HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
|
| - ActiveEntriesMap::const_iterator it = active_entries_.find(key);
|
| - return it != active_entries_.end() ? it->second : NULL;
|
| -}
|
| -
|
| -HttpCache::ActiveEntry* HttpCache::OpenEntry(const std::string& key) {
|
| - DCHECK(!FindActiveEntry(key));
|
| -
|
| - disk_cache::Entry* disk_entry;
|
| - if (!disk_cache_->OpenEntry(key, &disk_entry))
|
| - return NULL;
|
| -
|
| - return ActivateEntry(key, disk_entry);
|
| -}
|
| -
|
| -HttpCache::ActiveEntry* HttpCache::CreateEntry(const std::string& key) {
|
| - DCHECK(!FindActiveEntry(key));
|
| -
|
| - disk_cache::Entry* disk_entry;
|
| - if (!disk_cache_->CreateEntry(key, &disk_entry))
|
| - return NULL;
|
| -
|
| - return ActivateEntry(key, disk_entry);
|
| -}
|
| -
|
| -void HttpCache::DestroyEntry(ActiveEntry* entry) {
|
| - if (entry->doomed) {
|
| - FinalizeDoomedEntry(entry);
|
| - } else {
|
| - DeactivateEntry(entry);
|
| - }
|
| -}
|
| -
|
| -HttpCache::ActiveEntry* HttpCache::ActivateEntry(
|
| - const std::string& key,
|
| - disk_cache::Entry* disk_entry) {
|
| - ActiveEntry* entry = new ActiveEntry(disk_entry);
|
| - active_entries_[key] = entry;
|
| - return entry;
|
| -}
|
| -
|
| -void HttpCache::DeactivateEntry(ActiveEntry* entry) {
|
| - DCHECK(!entry->will_process_pending_queue);
|
| - DCHECK(!entry->doomed);
|
| - DCHECK(!entry->writer);
|
| - DCHECK(entry->readers.empty());
|
| - DCHECK(entry->pending_queue.empty());
|
| -
|
| - std::string key = entry->disk_entry->GetKey();
|
| - if (key.empty())
|
| - return SlowDeactivateEntry(entry);
|
| -
|
| - ActiveEntriesMap::iterator it = active_entries_.find(key);
|
| - DCHECK(it != active_entries_.end());
|
| - DCHECK(it->second == entry);
|
| -
|
| - active_entries_.erase(it);
|
| - delete entry;
|
| -}
|
| -
|
| -// We don't know this entry's key so we have to find it without it.
|
| -void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) {
|
| - for (ActiveEntriesMap::iterator it = active_entries_.begin();
|
| - it != active_entries_.end(); ++it) {
|
| - if (it->second == entry) {
|
| - active_entries_.erase(it);
|
| - delete entry;
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
|
| - DCHECK(entry);
|
| -
|
| - // We implement a basic reader/writer lock for the disk cache entry. If
|
| - // there is already a writer, then everyone has to wait for the writer to
|
| - // finish before they can access the cache entry. There can be multiple
|
| - // readers.
|
| - //
|
| - // NOTE: If the transaction can only write, then the entry should not be in
|
| - // use (since any existing entry should have already been doomed).
|
| -
|
| - if (entry->writer || entry->will_process_pending_queue) {
|
| - entry->pending_queue.push_back(trans);
|
| - return ERR_IO_PENDING;
|
| - }
|
| -
|
| - if (trans->mode() & Transaction::WRITE) {
|
| - // transaction needs exclusive access to the entry
|
| - if (entry->readers.empty()) {
|
| - entry->writer = trans;
|
| - } else {
|
| - entry->pending_queue.push_back(trans);
|
| - return ERR_IO_PENDING;
|
| - }
|
| - } else {
|
| - // transaction needs read access to the entry
|
| - entry->readers.push_back(trans);
|
| - }
|
| -
|
| - // We do this before calling EntryAvailable to force any further calls to
|
| - // AddTransactionToEntry to add their transaction to the pending queue, which
|
| - // ensures FIFO ordering.
|
| - if (!entry->writer && !entry->pending_queue.empty())
|
| - ProcessPendingQueue(entry);
|
| -
|
| - return trans->EntryAvailable(entry);
|
| -}
|
| -
|
| -void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
|
| - bool cancel) {
|
| - // If we already posted a task to move on to the next transaction and this was
|
| - // the writer, there is nothing to cancel.
|
| - if (entry->will_process_pending_queue && entry->readers.empty())
|
| - return;
|
| -
|
| - if (entry->writer) {
|
| - DCHECK(trans == entry->writer);
|
| -
|
| - // Assume there was a failure.
|
| - bool success = false;
|
| - if (cancel) {
|
| - DCHECK(entry->disk_entry);
|
| - // This is a successful operation in the sense that we want to keep the
|
| - // entry.
|
| - success = trans->AddTruncatedFlag();
|
| - }
|
| - DoneWritingToEntry(entry, success);
|
| - } else {
|
| - DoneReadingFromEntry(entry, trans);
|
| - }
|
| -}
|
| -
|
| -void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
|
| - DCHECK(entry->readers.empty());
|
| -
|
| - entry->writer = NULL;
|
| -
|
| - if (success) {
|
| - ProcessPendingQueue(entry);
|
| - } else {
|
| - DCHECK(!entry->will_process_pending_queue);
|
| -
|
| - // We failed to create this entry.
|
| - TransactionList pending_queue;
|
| - pending_queue.swap(entry->pending_queue);
|
| -
|
| - entry->disk_entry->Doom();
|
| - DestroyEntry(entry);
|
| -
|
| - // We need to do something about these pending entries, which now need to
|
| - // be added to a new entry.
|
| - while (!pending_queue.empty()) {
|
| - pending_queue.front()->AddToEntry();
|
| - pending_queue.pop_front();
|
| - }
|
| - }
|
| -}
|
| -
|
| -void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
|
| - DCHECK(!entry->writer);
|
| -
|
| - TransactionList::iterator it =
|
| - std::find(entry->readers.begin(), entry->readers.end(), trans);
|
| - DCHECK(it != entry->readers.end());
|
| -
|
| - entry->readers.erase(it);
|
| -
|
| - ProcessPendingQueue(entry);
|
| -}
|
| -
|
| -void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
|
| - DCHECK(entry->writer);
|
| - DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
|
| - DCHECK(entry->readers.empty());
|
| -
|
| - Transaction* trans = entry->writer;
|
| -
|
| - entry->writer = NULL;
|
| - entry->readers.push_back(trans);
|
| -
|
| - ProcessPendingQueue(entry);
|
| -}
|
| -
|
| -void HttpCache::RemovePendingTransaction(Transaction* trans) {
|
| - ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
|
| - bool found = false;
|
| - if (i != active_entries_.end())
|
| - found = RemovePendingTransactionFromEntry(i->second, trans);
|
| -
|
| - if (found)
|
| - return;
|
| -
|
| - ActiveEntriesSet::iterator it = doomed_entries_.begin();
|
| - for (; it != doomed_entries_.end() && !found; ++it)
|
| - found = RemovePendingTransactionFromEntry(*it, trans);
|
| -}
|
| -
|
| -bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
|
| - Transaction* trans) {
|
| - TransactionList& pending_queue = entry->pending_queue;
|
| -
|
| - TransactionList::iterator j =
|
| - find(pending_queue.begin(), pending_queue.end(), trans);
|
| - if (j == pending_queue.end())
|
| - return false;
|
| -
|
| - pending_queue.erase(j);
|
| - return true;
|
| -}
|
| -
|
| -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
|
| - // not delete the entry before OnProcessPendingQueue runs.
|
| - if (entry->will_process_pending_queue)
|
| - return;
|
| - entry->will_process_pending_queue = true;
|
| -
|
| - MessageLoop::current()->PostTask(FROM_HERE,
|
| - task_factory_.NewRunnableMethod(&HttpCache::OnProcessPendingQueue,
|
| - entry));
|
| -}
|
| -
|
| -void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
|
| - entry->will_process_pending_queue = false;
|
| - DCHECK(!entry->writer);
|
| -
|
| - // If no one is interested in this entry, then we can de-activate it.
|
| - if (entry->pending_queue.empty()) {
|
| - if (entry->readers.empty())
|
| - DestroyEntry(entry);
|
| - return;
|
| - }
|
| -
|
| - // Promote next transaction from the pending queue.
|
| - Transaction* next = entry->pending_queue.front();
|
| - if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
|
| - return; // Have to wait.
|
| -
|
| - entry->pending_queue.erase(entry->pending_queue.begin());
|
| -
|
| - AddTransactionToEntry(entry, next);
|
| -}
|
| -
|
| -void HttpCache::CloseIdleConnections() {
|
| - net::HttpNetworkLayer* network =
|
| - static_cast<net::HttpNetworkLayer*>(network_layer_.get());
|
| - HttpNetworkSession* session = network->GetSession();
|
| - if (session) {
|
| - session->tcp_socket_pool()->CloseIdleSockets();
|
| - }
|
| -}
|
| -
|
| -//-----------------------------------------------------------------------------
|
| -
|
| } // namespace net
|
|
|