Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Unified Diff: net/http/http_cache_transaction.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/http/http_cache_transaction.h ('k') | net/http/http_cache_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http/http_cache_transaction.cc
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
deleted file mode 100644
index 18ee59b1be04e78c31dc41e56768f4fe8d8b7a8c..0000000000000000000000000000000000000000
--- a/net/http/http_cache_transaction.cc
+++ /dev/null
@@ -1,3279 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// 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_transaction.h"
-
-#include "build/build_config.h"
-
-#if defined(OS_POSIX)
-#include <unistd.h>
-#endif
-
-#include <algorithm>
-#include <string>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/format_macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/profiler/scoped_tracker.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "net/base/completion_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/load_timing_info.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/upload_data_stream.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/disk_cache/disk_cache.h"
-#include "net/http/disk_based_cert_cache.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_transaction.h"
-#include "net/http/http_util.h"
-#include "net/http/partial_data.h"
-#include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_config_service.h"
-
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-
-namespace {
-
-// TODO(ricea): Move this to HttpResponseHeaders once it is standardised.
-static const char kFreshnessHeader[] = "Resource-Freshness";
-
-// Stores data relevant to the statistics of writing and reading entire
-// certificate chains using DiskBasedCertCache. |num_pending_ops| is the number
-// of certificates in the chain that have pending operations in the
-// DiskBasedCertCache. |start_time| is the time that the read and write
-// commands began being issued to the DiskBasedCertCache.
-// TODO(brandonsalmon): Remove this when it is no longer necessary to
-// collect data.
-class SharedChainData : public base::RefCounted<SharedChainData> {
- public:
- SharedChainData(int num_ops, TimeTicks start)
- : num_pending_ops(num_ops), start_time(start) {}
-
- int num_pending_ops;
- TimeTicks start_time;
-
- private:
- friend class base::RefCounted<SharedChainData>;
- ~SharedChainData() {}
- DISALLOW_COPY_AND_ASSIGN(SharedChainData);
-};
-
-// Used to obtain a cache entry key for an OSCertHandle.
-// TODO(brandonsalmon): Remove this when cache keys are stored
-// and no longer have to be recomputed to retrieve the OSCertHandle
-// from the disk.
-std::string GetCacheKeyForCert(net::X509Certificate::OSCertHandle cert_handle) {
- net::SHA1HashValue fingerprint =
- net::X509Certificate::CalculateFingerprint(cert_handle);
-
- return "cert:" +
- base::HexEncode(fingerprint.data, arraysize(fingerprint.data));
-}
-
-// |dist_from_root| indicates the position of the read certificate in the
-// certificate chain, 0 indicating it is the root. |is_leaf| indicates
-// whether or not the read certificate was the leaf of the chain.
-// |shared_chain_data| contains data shared by each certificate in
-// the chain.
-void OnCertReadIOComplete(
- int dist_from_root,
- bool is_leaf,
- const scoped_refptr<SharedChainData>& shared_chain_data,
- net::X509Certificate::OSCertHandle cert_handle) {
- // If |num_pending_ops| is one, this was the last pending read operation
- // for this chain of certificates. The total time used to read the chain
- // can be calculated by subtracting the starting time from Now().
- shared_chain_data->num_pending_ops--;
- if (!shared_chain_data->num_pending_ops) {
- const TimeDelta read_chain_wait =
- TimeTicks::Now() - shared_chain_data->start_time;
- UMA_HISTOGRAM_CUSTOM_TIMES("DiskBasedCertCache.ChainReadTime",
- read_chain_wait,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10),
- 50);
- }
-
- bool success = (cert_handle != NULL);
- if (is_leaf)
- UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.CertIoReadSuccessLeaf", success);
-
- if (success)
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "DiskBasedCertCache.CertIoReadSuccess", dist_from_root, 0, 10, 7);
- else
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "DiskBasedCertCache.CertIoReadFailure", dist_from_root, 0, 10, 7);
-}
-
-// |dist_from_root| indicates the position of the written certificate in the
-// certificate chain, 0 indicating it is the root. |is_leaf| indicates
-// whether or not the written certificate was the leaf of the chain.
-// |shared_chain_data| contains data shared by each certificate in
-// the chain.
-void OnCertWriteIOComplete(
- int dist_from_root,
- bool is_leaf,
- const scoped_refptr<SharedChainData>& shared_chain_data,
- const std::string& key) {
- // If |num_pending_ops| is one, this was the last pending write operation
- // for this chain of certificates. The total time used to write the chain
- // can be calculated by subtracting the starting time from Now().
- shared_chain_data->num_pending_ops--;
- if (!shared_chain_data->num_pending_ops) {
- const TimeDelta write_chain_wait =
- TimeTicks::Now() - shared_chain_data->start_time;
- UMA_HISTOGRAM_CUSTOM_TIMES("DiskBasedCertCache.ChainWriteTime",
- write_chain_wait,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10),
- 50);
- }
-
- bool success = !key.empty();
- if (is_leaf)
- UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.CertIoWriteSuccessLeaf", success);
-
- if (success)
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "DiskBasedCertCache.CertIoWriteSuccess", dist_from_root, 0, 10, 7);
- else
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "DiskBasedCertCache.CertIoWriteFailure", dist_from_root, 0, 10, 7);
-}
-
-// From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6
-// a "non-error response" is one with a 2xx (Successful) or 3xx
-// (Redirection) status code.
-bool NonErrorResponse(int status_code) {
- int status_code_range = status_code / 100;
- return status_code_range == 2 || status_code_range == 3;
-}
-
-// Error codes that will be considered indicative of a page being offline/
-// unreachable for LOAD_FROM_CACHE_IF_OFFLINE.
-bool IsOfflineError(int error) {
- return (error == net::ERR_NAME_NOT_RESOLVED ||
- error == net::ERR_INTERNET_DISCONNECTED ||
- error == net::ERR_ADDRESS_UNREACHABLE ||
- error == net::ERR_CONNECTION_TIMED_OUT);
-}
-
-// Enum for UMA, indicating the status (with regard to offline mode) of
-// a particular request.
-enum RequestOfflineStatus {
- // A cache transaction hit in cache (data was present and not stale)
- // and returned it.
- OFFLINE_STATUS_FRESH_CACHE,
-
- // A network request was required for a cache entry, and it succeeded.
- OFFLINE_STATUS_NETWORK_SUCCEEDED,
-
- // A network request was required for a cache entry, and it failed with
- // a non-offline error.
- OFFLINE_STATUS_NETWORK_FAILED,
-
- // A network request was required for a cache entry, it failed with an
- // offline error, and we could serve stale data if
- // LOAD_FROM_CACHE_IF_OFFLINE was set.
- OFFLINE_STATUS_DATA_AVAILABLE_OFFLINE,
-
- // A network request was required for a cache entry, it failed with
- // an offline error, and there was no servable data in cache (even
- // stale data).
- OFFLINE_STATUS_DATA_UNAVAILABLE_OFFLINE,
-
- OFFLINE_STATUS_MAX_ENTRIES
-};
-
-void RecordOfflineStatus(int load_flags, RequestOfflineStatus status) {
- // Restrict to main frame to keep statistics close to
- // "would have shown them something useful if offline mode was enabled".
- if (load_flags & net::LOAD_MAIN_FRAME) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.OfflineStatus", status,
- OFFLINE_STATUS_MAX_ENTRIES);
- }
-}
-
-void RecordNoStoreHeaderHistogram(int load_flags,
- const net::HttpResponseInfo* response) {
- if (load_flags & net::LOAD_MAIN_FRAME) {
- UMA_HISTOGRAM_BOOLEAN(
- "Net.MainFrameNoStore",
- response->headers->HasHeaderValue("cache-control", "no-store"));
- }
-}
-
-base::Value* NetLogAsyncRevalidationInfoCallback(
- const net::NetLog::Source& source,
- const net::HttpRequestInfo* request,
- net::NetLog::LogLevel log_level) {
- base::DictionaryValue* dict = new base::DictionaryValue();
- source.AddToEventParameters(dict);
-
- dict->SetString("url", request->url.possibly_invalid_spec());
- dict->SetString("method", request->method);
- return dict;
-}
-
-enum ExternallyConditionalizedType {
- EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION,
- EXTERNALLY_CONDITIONALIZED_CACHE_USABLE,
- EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS,
- EXTERNALLY_CONDITIONALIZED_MAX
-};
-
-} // namespace
-
-namespace net {
-
-struct HeaderNameAndValue {
- const char* name;
- const char* value;
-};
-
-// If the request includes one of these request headers, then avoid caching
-// to avoid getting confused.
-static const HeaderNameAndValue kPassThroughHeaders[] = {
- { "if-unmodified-since", NULL }, // causes unexpected 412s
- { "if-match", NULL }, // causes unexpected 412s
- { "if-range", NULL },
- { NULL, NULL }
-};
-
-struct ValidationHeaderInfo {
- const char* request_header_name;
- const char* related_response_header_name;
-};
-
-static const ValidationHeaderInfo kValidationHeaders[] = {
- { "if-modified-since", "last-modified" },
- { "if-none-match", "etag" },
-};
-
-// If the request includes one of these request headers, then avoid reusing
-// our cached copy if any.
-static const HeaderNameAndValue kForceFetchHeaders[] = {
- { "cache-control", "no-cache" },
- { "pragma", "no-cache" },
- { NULL, NULL }
-};
-
-// If the request includes one of these request headers, then force our
-// cached copy (if any) to be revalidated before reusing it.
-static const HeaderNameAndValue kForceValidateHeaders[] = {
- { "cache-control", "max-age=0" },
- { NULL, NULL }
-};
-
-static bool HeaderMatches(const HttpRequestHeaders& headers,
- const HeaderNameAndValue* search) {
- for (; search->name; ++search) {
- std::string header_value;
- if (!headers.GetHeader(search->name, &header_value))
- continue;
-
- if (!search->value)
- return true;
-
- HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ',');
- while (v.GetNext()) {
- if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value))
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-
-HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
- : next_state_(STATE_NONE),
- request_(NULL),
- priority_(priority),
- cache_(cache->GetWeakPtr()),
- entry_(NULL),
- new_entry_(NULL),
- new_response_(NULL),
- mode_(NONE),
- target_state_(STATE_NONE),
- reading_(false),
- invalid_range_(false),
- truncated_(false),
- is_sparse_(false),
- range_requested_(false),
- handling_206_(false),
- cache_pending_(false),
- done_reading_(false),
- vary_mismatch_(false),
- couldnt_conditionalize_request_(false),
- bypass_lock_for_test_(false),
- fail_conditionalization_for_test_(false),
- io_buf_len_(0),
- read_offset_(0),
- effective_load_flags_(0),
- write_len_(0),
- transaction_pattern_(PATTERN_UNDEFINED),
- total_received_bytes_(0),
- websocket_handshake_stream_base_create_helper_(NULL),
- weak_factory_(this) {
- static_assert(HttpCache::Transaction::kNumValidationHeaders ==
- arraysize(kValidationHeaders),
- "invalid number of validation headers");
-
- io_callback_ = base::Bind(&Transaction::OnIOComplete,
- weak_factory_.GetWeakPtr());
-}
-
-HttpCache::Transaction::~Transaction() {
- // We may have to issue another IO, but we should never invoke the callback_
- // after this point.
- callback_.Reset();
-
- if (cache_) {
- if (entry_) {
- bool cancel_request = reading_ && response_.headers.get();
- if (cancel_request) {
- if (partial_) {
- entry_->disk_entry->CancelSparseIO();
- } else {
- cancel_request &= (response_.headers->response_code() == 200);
- }
- }
-
- cache_->DoneWithEntry(entry_, this, cancel_request);
- } else if (cache_pending_) {
- cache_->RemovePendingTransaction(this);
- }
- }
-}
-
-int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
- const CompletionCallback& callback) {
- DCHECK(buf);
- DCHECK_GT(buf_len, 0);
- DCHECK(!callback.is_null());
- if (!cache_.get() || !entry_)
- return ERR_UNEXPECTED;
-
- // We don't need to track this operation for anything.
- // It could be possible to check if there is something already written and
- // avoid writing again (it should be the same, right?), but let's allow the
- // caller to "update" the contents with something new.
- return entry_->disk_entry->WriteData(kMetadataIndex, 0, buf, buf_len,
- callback, true);
-}
-
-bool HttpCache::Transaction::AddTruncatedFlag() {
- DCHECK(mode_ & WRITE || mode_ == NONE);
-
- // Don't set the flag for sparse entries.
- if (partial_.get() && !truncated_)
- return true;
-
- if (!CanResume(true))
- return false;
-
- // We may have received the whole resource already.
- if (done_reading_)
- return true;
-
- truncated_ = true;
- target_state_ = STATE_NONE;
- next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE;
- DoLoop(OK);
- return true;
-}
-
-LoadState HttpCache::Transaction::GetWriterLoadState() const {
- if (network_trans_.get())
- return network_trans_->GetLoadState();
- if (entry_ || !request_)
- return LOAD_STATE_IDLE;
- return LOAD_STATE_WAITING_FOR_CACHE;
-}
-
-const BoundNetLog& HttpCache::Transaction::net_log() const {
- return net_log_;
-}
-
-int HttpCache::Transaction::Start(const HttpRequestInfo* request,
- const CompletionCallback& callback,
- const BoundNetLog& net_log) {
- DCHECK(request);
- DCHECK(!callback.is_null());
-
- // Ensure that we only have one asynchronous call at a time.
- DCHECK(callback_.is_null());
- DCHECK(!reading_);
- DCHECK(!network_trans_.get());
- DCHECK(!entry_);
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- SetRequest(net_log, request);
-
- // We have to wait until the backend is initialized so we start the SM.
- next_state_ = STATE_GET_BACKEND;
- int rv = DoLoop(OK);
-
- // Setting this here allows us to check for the existence of a callback_ to
- // determine if we are still inside Start.
- if (rv == ERR_IO_PENDING) {
- callback_ = tracked_objects::ScopedTracker::TrackCallback(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::Start"),
- callback);
- }
-
- return rv;
-}
-
-int HttpCache::Transaction::RestartIgnoringLastError(
- const CompletionCallback& callback) {
- DCHECK(!callback.is_null());
-
- // Ensure that we only have one asynchronous call at a time.
- DCHECK(callback_.is_null());
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- int rv = RestartNetworkRequest();
-
- if (rv == ERR_IO_PENDING) {
- callback_ = tracked_objects::ScopedTracker::TrackCallback(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::RestartIgnoringLastError"),
- callback);
- }
-
- return rv;
-}
-
-int HttpCache::Transaction::RestartWithCertificate(
- X509Certificate* client_cert,
- const CompletionCallback& callback) {
- DCHECK(!callback.is_null());
-
- // Ensure that we only have one asynchronous call at a time.
- DCHECK(callback_.is_null());
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- int rv = RestartNetworkRequestWithCertificate(client_cert);
-
- if (rv == ERR_IO_PENDING) {
- callback_ = tracked_objects::ScopedTracker::TrackCallback(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::RestartWithCertificate"),
- callback);
- }
-
- return rv;
-}
-
-int HttpCache::Transaction::RestartWithAuth(
- const AuthCredentials& credentials,
- const CompletionCallback& callback) {
- DCHECK(auth_response_.headers.get());
- DCHECK(!callback.is_null());
-
- // Ensure that we only have one asynchronous call at a time.
- DCHECK(callback_.is_null());
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- // Clear the intermediate response since we are going to start over.
- auth_response_ = HttpResponseInfo();
-
- int rv = RestartNetworkRequestWithAuth(credentials);
-
- if (rv == ERR_IO_PENDING) {
- callback_ = tracked_objects::ScopedTracker::TrackCallback(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::RestartWithAuth"),
- callback);
- }
-
- return rv;
-}
-
-bool HttpCache::Transaction::IsReadyToRestartForAuth() {
- if (!network_trans_.get())
- return false;
- return network_trans_->IsReadyToRestartForAuth();
-}
-
-int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
- const CompletionCallback& callback) {
- DCHECK(buf);
- DCHECK_GT(buf_len, 0);
- DCHECK(!callback.is_null());
-
- DCHECK(callback_.is_null());
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- // If we have an intermediate auth response at this point, then it means the
- // user wishes to read the network response (the error page). If there is a
- // previous response in the cache then we should leave it intact.
- if (auth_response_.headers.get() && mode_ != NONE) {
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- DCHECK(mode_ & WRITE);
- DoneWritingToEntry(mode_ == READ_WRITE);
- mode_ = NONE;
- }
-
- reading_ = true;
- int rv;
-
- switch (mode_) {
- case READ_WRITE:
- DCHECK(partial_.get());
- if (!network_trans_.get()) {
- // We are just reading from the cache, but we may be writing later.
- rv = ReadFromEntry(buf, buf_len);
- break;
- }
- case NONE:
- case WRITE:
- DCHECK(network_trans_.get());
- rv = ReadFromNetwork(buf, buf_len);
- break;
- case READ:
- rv = ReadFromEntry(buf, buf_len);
- break;
- default:
- NOTREACHED();
- rv = ERR_FAILED;
- }
-
- if (rv == ERR_IO_PENDING) {
- DCHECK(callback_.is_null());
- callback_ = tracked_objects::ScopedTracker::TrackCallback(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 HttpCache::Transaction::Read"),
- callback);
- }
- return rv;
-}
-
-void HttpCache::Transaction::StopCaching() {
- // We really don't know where we are now. Hopefully there is no operation in
- // progress, but nothing really prevents this method to be called after we
- // returned ERR_IO_PENDING. We cannot attempt to truncate the entry at this
- // point because we need the state machine for that (and even if we are really
- // free, that would be an asynchronous operation). In other words, keep the
- // entry how it is (it will be marked as truncated at destruction), and let
- // the next piece of code that executes know that we are now reading directly
- // from the net.
- // TODO(mmenke): This doesn't release the lock on the cache entry, so a
- // future request for the resource will be blocked on this one.
- // Fix this.
- if (cache_.get() && entry_ && (mode_ & WRITE) && network_trans_.get() &&
- !is_sparse_ && !range_requested_) {
- mode_ = NONE;
- }
-}
-
-bool HttpCache::Transaction::GetFullRequestHeaders(
- HttpRequestHeaders* headers) const {
- if (network_trans_)
- return network_trans_->GetFullRequestHeaders(headers);
-
- // TODO(ttuttle): Read headers from cache.
- return false;
-}
-
-int64 HttpCache::Transaction::GetTotalReceivedBytes() const {
- int64 total_received_bytes = total_received_bytes_;
- if (network_trans_)
- total_received_bytes += network_trans_->GetTotalReceivedBytes();
- return total_received_bytes;
-}
-
-void HttpCache::Transaction::DoneReading() {
- if (cache_.get() && entry_) {
- DCHECK_NE(mode_, UPDATE);
- if (mode_ & WRITE) {
- DoneWritingToEntry(true);
- } else if (mode_ & READ) {
- // It is necessary to check mode_ & READ because it is possible
- // for mode_ to be NONE and entry_ non-NULL with a write entry
- // if StopCaching was called.
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
- }
- }
-}
-
-const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {
- // Null headers means we encountered an error or haven't a response yet
- if (auth_response_.headers.get())
- return &auth_response_;
- return (response_.headers.get() || response_.ssl_info.cert.get() ||
- response_.cert_request_info.get())
- ? &response_
- : NULL;
-}
-
-LoadState HttpCache::Transaction::GetLoadState() const {
- LoadState state = GetWriterLoadState();
- if (state != LOAD_STATE_WAITING_FOR_CACHE)
- return state;
-
- if (cache_.get())
- return cache_->GetLoadStateForPendingTransaction(this);
-
- return LOAD_STATE_IDLE;
-}
-
-UploadProgress HttpCache::Transaction::GetUploadProgress() const {
- if (network_trans_.get())
- return network_trans_->GetUploadProgress();
- return final_upload_progress_;
-}
-
-void HttpCache::Transaction::SetQuicServerInfo(
- QuicServerInfo* quic_server_info) {}
-
-bool HttpCache::Transaction::GetLoadTimingInfo(
- LoadTimingInfo* load_timing_info) const {
- if (network_trans_)
- return network_trans_->GetLoadTimingInfo(load_timing_info);
-
- if (old_network_trans_load_timing_) {
- *load_timing_info = *old_network_trans_load_timing_;
- return true;
- }
-
- if (first_cache_access_since_.is_null())
- return false;
-
- // If the cache entry was opened, return that time.
- load_timing_info->send_start = first_cache_access_since_;
- // This time doesn't make much sense when reading from the cache, so just use
- // the same time as send_start.
- load_timing_info->send_end = first_cache_access_since_;
- return true;
-}
-
-void HttpCache::Transaction::SetPriority(RequestPriority priority) {
- priority_ = priority;
- if (network_trans_)
- network_trans_->SetPriority(priority_);
-}
-
-void HttpCache::Transaction::SetWebSocketHandshakeStreamCreateHelper(
- WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
- websocket_handshake_stream_base_create_helper_ = create_helper;
- if (network_trans_)
- network_trans_->SetWebSocketHandshakeStreamCreateHelper(create_helper);
-}
-
-void HttpCache::Transaction::SetBeforeNetworkStartCallback(
- const BeforeNetworkStartCallback& callback) {
- DCHECK(!network_trans_);
- before_network_start_callback_ = callback;
-}
-
-void HttpCache::Transaction::SetBeforeProxyHeadersSentCallback(
- const BeforeProxyHeadersSentCallback& callback) {
- DCHECK(!network_trans_);
- before_proxy_headers_sent_callback_ = callback;
-}
-
-int HttpCache::Transaction::ResumeNetworkStart() {
- if (network_trans_)
- return network_trans_->ResumeNetworkStart();
- return ERR_UNEXPECTED;
-}
-
-//-----------------------------------------------------------------------------
-
-void HttpCache::Transaction::DoCallback(int rv) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCallback"));
-
- DCHECK(rv != ERR_IO_PENDING);
- DCHECK(!callback_.is_null());
-
- read_buf_ = NULL; // Release the buffer before invoking the callback.
-
- // Since Run may result in Read being called, clear callback_ up front.
- CompletionCallback c = callback_;
- callback_.Reset();
- c.Run(rv);
-}
-
-int HttpCache::Transaction::HandleResult(int rv) {
- DCHECK(rv != ERR_IO_PENDING);
- if (!callback_.is_null())
- DoCallback(rv);
-
- return rv;
-}
-
-// A few common patterns: (Foo* means Foo -> FooComplete)
-//
-// 1. Not-cached entry:
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* ->
-// SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
-// CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* ->
-// PartialHeadersReceived
-//
-// Read():
-// NetworkRead* -> CacheWriteData*
-//
-// 2. Cached entry, no validation:
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
-// -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-// BeginCacheValidation() -> SetupEntryForRead()
-//
-// Read():
-// CacheReadData*
-//
-// 3. Cached entry, validation (304):
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
-// -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
-// UpdateCachedResponse -> CacheWriteResponse* -> UpdateCachedResponseComplete
-// -> OverwriteCachedResponse -> PartialHeadersReceived
-//
-// Read():
-// CacheReadData*
-//
-// 4. Cached entry, validation and replace (200):
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
-// -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
-// OverwriteCachedResponse -> CacheWriteResponse* -> DoTruncateCachedData* ->
-// TruncateCachedMetadata* -> PartialHeadersReceived
-//
-// Read():
-// NetworkRead* -> CacheWriteData*
-//
-// 5. Sparse entry, partially cached, byte range request:
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
-// -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-// CacheQueryData* -> ValidateEntryHeadersAndContinue() ->
-// StartPartialCacheValidation -> CompletePartialCacheValidation ->
-// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
-// UpdateCachedResponse -> CacheWriteResponse* -> UpdateCachedResponseComplete
-// -> OverwriteCachedResponse -> PartialHeadersReceived
-//
-// Read() 1:
-// NetworkRead* -> CacheWriteData*
-//
-// Read() 2:
-// NetworkRead* -> CacheWriteData* -> StartPartialCacheValidation ->
-// CompletePartialCacheValidation -> CacheReadData* ->
-//
-// Read() 3:
-// CacheReadData* -> StartPartialCacheValidation ->
-// CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* ->
-// SuccessfulSendRequest -> UpdateCachedResponse* -> OverwriteCachedResponse
-// -> PartialHeadersReceived -> NetworkRead* -> CacheWriteData*
-//
-// 6. HEAD. Not-cached entry:
-// Pass through. Don't save a HEAD by itself.
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> SendRequest*
-//
-// 7. HEAD. Cached entry, no validation:
-// Start():
-// The same flow as for a GET request (example #2)
-//
-// Read():
-// CacheReadData (returns 0)
-//
-// 8. HEAD. Cached entry, validation (304):
-// The request updates the stored headers.
-// Start(): Same as for a GET request (example #3)
-//
-// Read():
-// CacheReadData (returns 0)
-//
-// 9. HEAD. Cached entry, validation and replace (200):
-// Pass through. The request dooms the old entry, as a HEAD won't be stored by
-// itself.
-// Start():
-// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
-// -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
-// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
-// OverwriteCachedResponse
-//
-// 10. HEAD. Sparse entry, partially cached:
-// Serve the request from the cache, as long as it doesn't require
-// revalidation. Ignore missing ranges when deciding to revalidate. If the
-// entry requires revalidation, ignore the whole request and go to full pass
-// through (the result of the HEAD request will NOT update the entry).
-//
-// Start(): Basically the same as example 7, as we never create a partial_
-// object for this request.
-//
-// 11. Prefetch, not-cached entry:
-// The same as example 1. The "unused_since_prefetch" bit is stored as true in
-// UpdateCachedResponse.
-//
-// 12. Prefetch, cached entry:
-// Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between
-// CacheReadResponse* and CacheDispatchValidation if the unused_since_prefetch
-// bit is unset.
-//
-// 13. Cached entry less than 5 minutes old, unused_since_prefetch is true:
-// Skip validation, similar to example 2.
-// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
-// -> CacheToggleUnusedSincePrefetch* -> CacheDispatchValidation ->
-// BeginPartialCacheValidation() -> BeginCacheValidation() ->
-// SetupEntryForRead()
-//
-// Read():
-// CacheReadData*
-//
-// 14. Cached entry more than 5 minutes old, unused_since_prefetch is true:
-// Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between
-// CacheReadResponse* and CacheDispatchValidation.
-int HttpCache::Transaction::DoLoop(int result) {
- DCHECK(next_state_ != STATE_NONE);
-
- int rv = result;
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_GET_BACKEND:
- DCHECK_EQ(OK, rv);
- rv = DoGetBackend();
- break;
- case STATE_GET_BACKEND_COMPLETE:
- rv = DoGetBackendComplete(rv);
- break;
- case STATE_SEND_REQUEST:
- DCHECK_EQ(OK, rv);
- rv = DoSendRequest();
- break;
- case STATE_SEND_REQUEST_COMPLETE:
- rv = DoSendRequestComplete(rv);
- break;
- case STATE_SUCCESSFUL_SEND_REQUEST:
- DCHECK_EQ(OK, rv);
- rv = DoSuccessfulSendRequest();
- break;
- case STATE_NETWORK_READ:
- DCHECK_EQ(OK, rv);
- rv = DoNetworkRead();
- break;
- case STATE_NETWORK_READ_COMPLETE:
- rv = DoNetworkReadComplete(rv);
- break;
- case STATE_INIT_ENTRY:
- DCHECK_EQ(OK, rv);
- rv = DoInitEntry();
- break;
- case STATE_OPEN_ENTRY:
- DCHECK_EQ(OK, rv);
- rv = DoOpenEntry();
- break;
- case STATE_OPEN_ENTRY_COMPLETE:
- rv = DoOpenEntryComplete(rv);
- break;
- case STATE_CREATE_ENTRY:
- DCHECK_EQ(OK, rv);
- rv = DoCreateEntry();
- break;
- case STATE_CREATE_ENTRY_COMPLETE:
- rv = DoCreateEntryComplete(rv);
- break;
- case STATE_DOOM_ENTRY:
- DCHECK_EQ(OK, rv);
- rv = DoDoomEntry();
- break;
- case STATE_DOOM_ENTRY_COMPLETE:
- rv = DoDoomEntryComplete(rv);
- break;
- case STATE_ADD_TO_ENTRY:
- DCHECK_EQ(OK, rv);
- rv = DoAddToEntry();
- break;
- case STATE_ADD_TO_ENTRY_COMPLETE:
- rv = DoAddToEntryComplete(rv);
- break;
- case STATE_START_PARTIAL_CACHE_VALIDATION:
- DCHECK_EQ(OK, rv);
- rv = DoStartPartialCacheValidation();
- break;
- case STATE_COMPLETE_PARTIAL_CACHE_VALIDATION:
- rv = DoCompletePartialCacheValidation(rv);
- break;
- case STATE_UPDATE_CACHED_RESPONSE:
- DCHECK_EQ(OK, rv);
- rv = DoUpdateCachedResponse();
- break;
- case STATE_UPDATE_CACHED_RESPONSE_COMPLETE:
- rv = DoUpdateCachedResponseComplete(rv);
- break;
- case STATE_OVERWRITE_CACHED_RESPONSE:
- DCHECK_EQ(OK, rv);
- rv = DoOverwriteCachedResponse();
- break;
- case STATE_TRUNCATE_CACHED_DATA:
- DCHECK_EQ(OK, rv);
- rv = DoTruncateCachedData();
- break;
- case STATE_TRUNCATE_CACHED_DATA_COMPLETE:
- rv = DoTruncateCachedDataComplete(rv);
- break;
- case STATE_TRUNCATE_CACHED_METADATA:
- DCHECK_EQ(OK, rv);
- rv = DoTruncateCachedMetadata();
- break;
- case STATE_TRUNCATE_CACHED_METADATA_COMPLETE:
- rv = DoTruncateCachedMetadataComplete(rv);
- break;
- case STATE_PARTIAL_HEADERS_RECEIVED:
- DCHECK_EQ(OK, rv);
- rv = DoPartialHeadersReceived();
- break;
- case STATE_CACHE_READ_RESPONSE:
- DCHECK_EQ(OK, rv);
- rv = DoCacheReadResponse();
- break;
- case STATE_CACHE_READ_RESPONSE_COMPLETE:
- rv = DoCacheReadResponseComplete(rv);
- break;
- case STATE_CACHE_DISPATCH_VALIDATION:
- DCHECK_EQ(OK, rv);
- rv = DoCacheDispatchValidation();
- break;
- case STATE_TOGGLE_UNUSED_SINCE_PREFETCH:
- DCHECK_EQ(OK, rv);
- rv = DoCacheToggleUnusedSincePrefetch();
- break;
- case STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE:
- rv = DoCacheToggleUnusedSincePrefetchComplete(rv);
- break;
- case STATE_CACHE_WRITE_RESPONSE:
- DCHECK_EQ(OK, rv);
- rv = DoCacheWriteResponse();
- break;
- case STATE_CACHE_WRITE_TRUNCATED_RESPONSE:
- DCHECK_EQ(OK, rv);
- rv = DoCacheWriteTruncatedResponse();
- break;
- case STATE_CACHE_WRITE_RESPONSE_COMPLETE:
- rv = DoCacheWriteResponseComplete(rv);
- break;
- case STATE_CACHE_READ_METADATA:
- DCHECK_EQ(OK, rv);
- rv = DoCacheReadMetadata();
- break;
- case STATE_CACHE_READ_METADATA_COMPLETE:
- rv = DoCacheReadMetadataComplete(rv);
- break;
- case STATE_CACHE_QUERY_DATA:
- DCHECK_EQ(OK, rv);
- rv = DoCacheQueryData();
- break;
- case STATE_CACHE_QUERY_DATA_COMPLETE:
- rv = DoCacheQueryDataComplete(rv);
- break;
- case STATE_CACHE_READ_DATA:
- DCHECK_EQ(OK, rv);
- rv = DoCacheReadData();
- break;
- case STATE_CACHE_READ_DATA_COMPLETE:
- rv = DoCacheReadDataComplete(rv);
- break;
- case STATE_CACHE_WRITE_DATA:
- rv = DoCacheWriteData(rv);
- break;
- case STATE_CACHE_WRITE_DATA_COMPLETE:
- rv = DoCacheWriteDataComplete(rv);
- break;
- default:
- NOTREACHED() << "bad state";
- rv = ERR_FAILED;
- break;
- }
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
-
- if (rv != ERR_IO_PENDING)
- HandleResult(rv);
-
- return rv;
-}
-
-int HttpCache::Transaction::DoGetBackend() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoGetBackend"));
-
- cache_pending_ = true;
- next_state_ = STATE_GET_BACKEND_COMPLETE;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_GET_BACKEND);
- return cache_->GetBackendForTransaction(this);
-}
-
-int HttpCache::Transaction::DoGetBackendComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoGetBackendComplete"));
-
- DCHECK(result == OK || result == ERR_FAILED);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_GET_BACKEND,
- result);
- cache_pending_ = false;
-
- if (!ShouldPassThrough()) {
- cache_key_ = cache_->GenerateCacheKey(request_);
-
- // Requested cache access mode.
- if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
- mode_ = READ;
- } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
- mode_ = WRITE;
- } else {
- mode_ = READ_WRITE;
- }
-
- // Downgrade to UPDATE if the request has been externally conditionalized.
- if (external_validation_.initialized) {
- if (mode_ & WRITE) {
- // Strip off the READ_DATA bit (and maybe add back a READ_META bit
- // in case READ was off).
- mode_ = UPDATE;
- } else {
- mode_ = NONE;
- }
- }
- }
-
- // Use PUT and DELETE only to invalidate existing stored entries.
- if ((request_->method == "PUT" || request_->method == "DELETE") &&
- mode_ != READ_WRITE && mode_ != WRITE) {
- mode_ = NONE;
- }
-
- // Note that if mode_ == UPDATE (which is tied to external_validation_), the
- // transaction behaves the same for GET and HEAD requests at this point: if it
- // was not modified, the entry is updated and a response is not returned from
- // the cache. If we receive 200, it doesn't matter if there was a validation
- // header or not.
- if (request_->method == "HEAD" && mode_ == WRITE)
- mode_ = NONE;
-
- // If must use cache, then we must fail. This can happen for back/forward
- // navigations to a page generated via a form post.
- if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE)
- return ERR_CACHE_MISS;
-
- if (mode_ == NONE) {
- if (partial_.get()) {
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- partial_.reset();
- }
- next_state_ = STATE_SEND_REQUEST;
- } else {
- next_state_ = STATE_INIT_ENTRY;
- }
-
- // This is only set if we have something to do with the response.
- range_requested_ = (partial_.get() != NULL);
-
- return OK;
-}
-
-int HttpCache::Transaction::DoSendRequest() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoSendRequest"));
-
- DCHECK(mode_ & WRITE || mode_ == NONE);
- DCHECK(!network_trans_.get());
-
- send_request_since_ = TimeTicks::Now();
-
- // Create a network transaction.
- int rv = cache_->network_layer_->CreateTransaction(priority_,
- &network_trans_);
- if (rv != OK)
- return rv;
- network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_);
- network_trans_->SetBeforeProxyHeadersSentCallback(
- before_proxy_headers_sent_callback_);
-
- // Old load timing information, if any, is now obsolete.
- old_network_trans_load_timing_.reset();
-
- if (websocket_handshake_stream_base_create_helper_)
- network_trans_->SetWebSocketHandshakeStreamCreateHelper(
- websocket_handshake_stream_base_create_helper_);
-
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
- rv = network_trans_->Start(request_, io_callback_, net_log_);
- return rv;
-}
-
-int HttpCache::Transaction::DoSendRequestComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoSendRequestComplete"));
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- // If requested, and we have a readable cache entry, and we have
- // an error indicating that we're offline as opposed to in contact
- // with a bad server, read from cache anyway.
- if (IsOfflineError(result)) {
- if (mode_ == READ_WRITE && entry_ && !partial_) {
- RecordOfflineStatus(effective_load_flags_,
- OFFLINE_STATUS_DATA_AVAILABLE_OFFLINE);
- if (effective_load_flags_ & LOAD_FROM_CACHE_IF_OFFLINE) {
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- response_.server_data_unavailable = true;
- return SetupEntryForRead();
- }
- } else {
- RecordOfflineStatus(effective_load_flags_,
- OFFLINE_STATUS_DATA_UNAVAILABLE_OFFLINE);
- }
- } else {
- RecordOfflineStatus(effective_load_flags_,
- (result == OK ? OFFLINE_STATUS_NETWORK_SUCCEEDED :
- OFFLINE_STATUS_NETWORK_FAILED));
- }
-
- // If we tried to conditionalize the request and failed, we know
- // we won't be reading from the cache after this point.
- if (couldnt_conditionalize_request_)
- mode_ = WRITE;
-
- if (result == OK) {
- next_state_ = STATE_SUCCESSFUL_SEND_REQUEST;
- return OK;
- }
-
- // Do not record requests that have network errors or restarts.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- if (IsCertificateError(result)) {
- const HttpResponseInfo* response = network_trans_->GetResponseInfo();
- // If we get a certificate error, then there is a certificate in ssl_info,
- // so GetResponseInfo() should never return NULL here.
- DCHECK(response);
- response_.ssl_info = response->ssl_info;
- } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
- const HttpResponseInfo* response = network_trans_->GetResponseInfo();
- DCHECK(response);
- response_.cert_request_info = response->cert_request_info;
- } else if (response_.was_cached) {
- DoneWritingToEntry(true);
- }
- return result;
-}
-
-// We received the response headers and there is no error.
-int HttpCache::Transaction::DoSuccessfulSendRequest() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoSuccessfulSendRequest"));
-
- DCHECK(!new_response_);
- const HttpResponseInfo* new_response = network_trans_->GetResponseInfo();
- bool authentication_failure = false;
-
- if (new_response->headers->response_code() == 401 ||
- new_response->headers->response_code() == 407) {
- auth_response_ = *new_response;
- if (!reading_)
- return OK;
-
- // We initiated a second request the caller doesn't know about. We should be
- // able to authenticate this request because we should have authenticated
- // this URL moments ago.
- if (IsReadyToRestartForAuth()) {
- DCHECK(!response_.auth_challenge.get());
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
- // In theory we should check to see if there are new cookies, but there
- // is no way to do that from here.
- return network_trans_->RestartWithAuth(AuthCredentials(), io_callback_);
- }
-
- // We have to perform cleanup at this point so that at least the next
- // request can succeed.
- authentication_failure = true;
- if (entry_)
- DoomPartialEntry(false);
- mode_ = NONE;
- partial_.reset();
- }
-
- new_response_ = new_response;
- if (authentication_failure ||
- (!ValidatePartialResponse() && !auth_response_.headers.get())) {
- // Something went wrong with this request and we have to restart it.
- // If we have an authentication response, we are exposed to weird things
- // hapenning if the user cancels the authentication before we receive
- // the new response.
- net_log_.AddEvent(NetLog::TYPE_HTTP_CACHE_RE_SEND_PARTIAL_REQUEST);
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- response_ = HttpResponseInfo();
- ResetNetworkTransaction();
- new_response_ = NULL;
- next_state_ = STATE_SEND_REQUEST;
- return OK;
- }
-
- if (handling_206_ && mode_ == READ_WRITE && !truncated_ && !is_sparse_) {
- // We have stored the full entry, but it changed and the server is
- // sending a range. We have to delete the old entry.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- DoneWritingToEntry(false);
- }
-
- if (mode_ == WRITE &&
- transaction_pattern_ != PATTERN_ENTRY_CANT_CONDITIONALIZE) {
- UpdateTransactionPattern(PATTERN_ENTRY_NOT_CACHED);
- }
-
- // Invalidate any cached GET with a successful PUT or DELETE.
- if (mode_ == WRITE &&
- (request_->method == "PUT" || request_->method == "DELETE")) {
- if (NonErrorResponse(new_response->headers->response_code())) {
- int ret = cache_->DoomEntry(cache_key_, NULL);
- DCHECK_EQ(OK, ret);
- }
- cache_->DoneWritingToEntry(entry_, true);
- entry_ = NULL;
- mode_ = NONE;
- }
-
- // Invalidate any cached GET with a successful POST.
- if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) &&
- request_->method == "POST" &&
- NonErrorResponse(new_response->headers->response_code())) {
- cache_->DoomMainEntryForUrl(request_->url);
- }
-
- RecordNoStoreHeaderHistogram(request_->load_flags, new_response);
-
- if (new_response_->headers->response_code() == 416 &&
- (request_->method == "GET" || request_->method == "POST")) {
- // If there is an active entry it may be destroyed with this transaction.
- response_ = *new_response_;
- return OK;
- }
-
- // Are we expecting a response to a conditional query?
- if (mode_ == READ_WRITE || mode_ == UPDATE) {
- if (new_response->headers->response_code() == 304 || handling_206_) {
- UpdateTransactionPattern(PATTERN_ENTRY_VALIDATED);
- next_state_ = STATE_UPDATE_CACHED_RESPONSE;
- return OK;
- }
- UpdateTransactionPattern(PATTERN_ENTRY_UPDATED);
- mode_ = WRITE;
- }
-
- next_state_ = STATE_OVERWRITE_CACHED_RESPONSE;
- return OK;
-}
-
-int HttpCache::Transaction::DoNetworkRead() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoNetworkRead"));
-
- next_state_ = STATE_NETWORK_READ_COMPLETE;
- return network_trans_->Read(read_buf_.get(), io_buf_len_, io_callback_);
-}
-
-int HttpCache::Transaction::DoNetworkReadComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoNetworkReadComplete"));
-
- DCHECK(mode_ & WRITE || mode_ == NONE);
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- // If there is an error or we aren't saving the data, we are done; just wait
- // until the destructor runs to see if we can keep the data.
- if (mode_ == NONE || result < 0)
- return result;
-
- next_state_ = STATE_CACHE_WRITE_DATA;
- return result;
-}
-
-int HttpCache::Transaction::DoInitEntry() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoInitEntry"));
-
- DCHECK(!new_entry_);
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- if (mode_ == WRITE) {
- next_state_ = STATE_DOOM_ENTRY;
- return OK;
- }
-
- next_state_ = STATE_OPEN_ENTRY;
- return OK;
-}
-
-int HttpCache::Transaction::DoOpenEntry() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoOpenEntry"));
-
- DCHECK(!new_entry_);
- next_state_ = STATE_OPEN_ENTRY_COMPLETE;
- cache_pending_ = true;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
- first_cache_access_since_ = TimeTicks::Now();
- return cache_->OpenEntry(cache_key_, &new_entry_, this);
-}
-
-int HttpCache::Transaction::DoOpenEntryComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoOpenEntryComplete"));
-
- // 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.
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result);
- 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 (request_->method == "PUT" || request_->method == "DELETE" ||
- (request_->method == "HEAD" && mode_ == READ_WRITE)) {
- DCHECK(mode_ == READ_WRITE || mode_ == WRITE || request_->method == "HEAD");
- mode_ = NONE;
- next_state_ = STATE_SEND_REQUEST;
- return OK;
- }
-
- if (mode_ == READ_WRITE) {
- mode_ = WRITE;
- next_state_ = STATE_CREATE_ENTRY;
- return OK;
- }
- if (mode_ == UPDATE) {
- // There is no cache entry to update; proceed without caching.
- mode_ = NONE;
- next_state_ = STATE_SEND_REQUEST;
- return OK;
- }
- if (cache_->mode() == PLAYBACK)
- DVLOG(1) << "Playback Cache Miss: " << request_->url;
-
- // The entry does not exist, and we are not permitted to create a new entry,
- // so we must fail.
- return ERR_CACHE_MISS;
-}
-
-int HttpCache::Transaction::DoCreateEntry() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCreateEntry"));
-
- DCHECK(!new_entry_);
- next_state_ = STATE_CREATE_ENTRY_COMPLETE;
- cache_pending_ = true;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
- return cache_->CreateEntry(cache_key_, &new_entry_, this);
-}
-
-int HttpCache::Transaction::DoCreateEntryComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCreateEntryComplete"));
-
- // 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.
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY,
- result);
- cache_pending_ = false;
- next_state_ = STATE_ADD_TO_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
- // OpenOrCreate() method exposed by the disk cache.
- DLOG(WARNING) << "Unable to create cache entry";
- mode_ = NONE;
- if (partial_.get())
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- next_state_ = STATE_SEND_REQUEST;
- }
- return OK;
-}
-
-int HttpCache::Transaction::DoDoomEntry() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoDoomEntry"));
-
- next_state_ = STATE_DOOM_ENTRY_COMPLETE;
- cache_pending_ = true;
- if (first_cache_access_since_.is_null())
- first_cache_access_since_ = TimeTicks::Now();
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY);
- return cache_->DoomEntry(cache_key_, this);
-}
-
-int HttpCache::Transaction::DoDoomEntryComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoDoomEntryComplete"));
-
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result);
- next_state_ = STATE_CREATE_ENTRY;
- cache_pending_ = false;
- if (result == ERR_CACHE_RACE)
- next_state_ = STATE_INIT_ENTRY;
- return OK;
-}
-
-int HttpCache::Transaction::DoAddToEntry() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoAddToEntry"));
-
- DCHECK(new_entry_);
- cache_pending_ = true;
- next_state_ = STATE_ADD_TO_ENTRY_COMPLETE;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY);
- DCHECK(entry_lock_waiting_since_.is_null());
- entry_lock_waiting_since_ = TimeTicks::Now();
- int rv = cache_->AddTransactionToEntry(new_entry_, this);
- if (rv == ERR_IO_PENDING) {
- if (bypass_lock_for_test_) {
- OnAddToEntryTimeout(entry_lock_waiting_since_);
- } else {
- int timeout_milliseconds = 20 * 1000;
- if (partial_ && new_entry_->writer &&
- new_entry_->writer->range_requested_) {
- // Quickly timeout and bypass the cache if we're a range request and
- // we're blocked by the reader/writer lock. Doing so eliminates a long
- // running issue, http://crbug.com/31014, where two of the same media
- // resources could not be played back simultaneously due to one locking
- // the cache entry until the entire video was downloaded.
- //
- // Bypassing the cache is not ideal, as we are now ignoring the cache
- // entirely for all range requests to a resource beyond the first. This
- // is however a much more succinct solution than the alternatives, which
- // would require somewhat significant changes to the http caching logic.
- //
- // Allow some timeout slack for the entry addition to complete in case
- // the writer lock is imminently released; we want to avoid skipping
- // the cache if at all possible. See http://crbug.com/408765
- timeout_milliseconds = 25;
- }
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
- weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
- TimeDelta::FromMilliseconds(timeout_milliseconds));
- }
- }
- return rv;
-}
-
-int HttpCache::Transaction::DoAddToEntryComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoAddToEntryComplete"));
-
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY,
- result);
- const TimeDelta entry_lock_wait =
- TimeTicks::Now() - entry_lock_waiting_since_;
- UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait);
-
- entry_lock_waiting_since_ = TimeTicks();
- DCHECK(new_entry_);
- cache_pending_ = false;
-
- if (result == OK)
- entry_ = new_entry_;
-
- // If there is a failure, the cache should have taken care of new_entry_.
- new_entry_ = NULL;
-
- if (result == ERR_CACHE_RACE) {
- next_state_ = STATE_INIT_ENTRY;
- return OK;
- }
-
- if (result == ERR_CACHE_LOCK_TIMEOUT) {
- // The cache is busy, bypass it for this transaction.
- mode_ = NONE;
- next_state_ = STATE_SEND_REQUEST;
- if (partial_) {
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- partial_.reset();
- }
- return OK;
- }
-
- if (result != OK) {
- NOTREACHED();
- return result;
- }
-
- if (mode_ == WRITE) {
- if (partial_.get())
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- next_state_ = STATE_SEND_REQUEST;
- } else {
- // We have to read the headers from the cached entry.
- DCHECK(mode_ & READ_META);
- next_state_ = STATE_CACHE_READ_RESPONSE;
- }
- return OK;
-}
-
-// We may end up here multiple times for a given request.
-int HttpCache::Transaction::DoStartPartialCacheValidation() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoStartPartialCacheValidation"));
-
- if (mode_ == NONE)
- return OK;
-
- next_state_ = STATE_COMPLETE_PARTIAL_CACHE_VALIDATION;
- return partial_->ShouldValidateCache(entry_->disk_entry, io_callback_);
-}
-
-int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCompletePartialCacheValidation"));
-
- if (!result) {
- // This is the end of the request.
- if (mode_ & WRITE) {
- DoneWritingToEntry(true);
- } else {
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
- }
- return result;
- }
-
- if (result < 0)
- return result;
-
- partial_->PrepareCacheValidation(entry_->disk_entry,
- &custom_request_->extra_headers);
-
- if (reading_ && partial_->IsCurrentRangeCached()) {
- next_state_ = STATE_CACHE_READ_DATA;
- return OK;
- }
-
- return BeginCacheValidation();
-}
-
-// We received 304 or 206 and we want to update the cached response headers.
-int HttpCache::Transaction::DoUpdateCachedResponse() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoUpdateCachedResponse"));
-
- next_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE;
- int rv = OK;
- // Update cached response based on headers in new_response.
- // TODO(wtc): should we update cached certificate (response_.ssl_info), too?
- response_.headers->Update(*new_response_->headers.get());
- response_.response_time = new_response_->response_time;
- response_.request_time = new_response_->request_time;
- response_.network_accessed = new_response_->network_accessed;
- response_.unused_since_prefetch = new_response_->unused_since_prefetch;
-
- if (response_.headers->HasHeaderValue("cache-control", "no-store")) {
- if (!entry_->doomed) {
- 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.
- if (!reading_) {
- target_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE;
- next_state_ = STATE_CACHE_WRITE_RESPONSE;
- rv = OK;
- }
- }
- return rv;
-}
-
-int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoUpdateCachedResponseComplete"));
-
- if (mode_ == UPDATE) {
- DCHECK(!handling_206_);
- // We got a "not modified" response and already updated the corresponding
- // cache entry above.
- //
- // By closing the cached entry now, we make sure that the 304 rather than
- // the cached 200 response, is what will be returned to the user.
- DoneWritingToEntry(true);
- } else if (entry_ && !handling_206_) {
- DCHECK_EQ(READ_WRITE, mode_);
- if (!partial_.get() || partial_->IsLastRange()) {
- cache_->ConvertWriterToReader(entry_);
- mode_ = READ;
- }
- // We no longer need the network transaction, so destroy it.
- final_upload_progress_ = network_trans_->GetUploadProgress();
- ResetNetworkTransaction();
- } else if (entry_ && handling_206_ && truncated_ &&
- partial_->initial_validation()) {
- // We just finished the validation of a truncated entry, and the server
- // is willing to resume the operation. Now we go back and start serving
- // the first part to the user.
- ResetNetworkTransaction();
- new_response_ = NULL;
- next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
- partial_->SetRangeToStartDownload();
- return OK;
- }
- next_state_ = STATE_OVERWRITE_CACHED_RESPONSE;
- return OK;
-}
-
-int HttpCache::Transaction::DoOverwriteCachedResponse() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoOverwriteCachedResponse"));
-
- if (mode_ & READ) {
- next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
- return OK;
- }
-
- // We change the value of Content-Length for partial content.
- if (handling_206_ && partial_.get())
- partial_->FixContentLength(new_response_->headers.get());
-
- response_ = *new_response_;
-
- if (request_->method == "HEAD") {
- // This response is replacing the cached one.
- DoneWritingToEntry(false);
- mode_ = NONE;
- new_response_ = NULL;
- return OK;
- }
-
- if (handling_206_ && !CanResume(false)) {
- // There is no point in storing this resource because it will never be used.
- // This may change if we support LOAD_ONLY_FROM_CACHE with sparse entries.
- DoneWritingToEntry(false);
- if (partial_.get())
- partial_->FixResponseHeaders(response_.headers.get(), true);
- next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
- return OK;
- }
-
- target_state_ = STATE_TRUNCATE_CACHED_DATA;
- next_state_ = truncated_ ? STATE_CACHE_WRITE_TRUNCATED_RESPONSE :
- STATE_CACHE_WRITE_RESPONSE;
- return OK;
-}
-
-int HttpCache::Transaction::DoTruncateCachedData() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoTruncateCachedData"));
-
- next_state_ = STATE_TRUNCATE_CACHED_DATA_COMPLETE;
- if (!entry_)
- return OK;
- if (net_log_.IsLogging())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
- // Truncate the stream.
- return WriteToEntry(kResponseContentIndex, 0, NULL, 0, io_callback_);
-}
-
-int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoTruncateCachedDataComplete"));
-
- if (entry_) {
- if (net_log_.IsLogging()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
- result);
- }
- }
-
- next_state_ = STATE_TRUNCATE_CACHED_METADATA;
- return OK;
-}
-
-int HttpCache::Transaction::DoTruncateCachedMetadata() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoTruncateCachedMetadata"));
-
- next_state_ = STATE_TRUNCATE_CACHED_METADATA_COMPLETE;
- if (!entry_)
- return OK;
-
- if (net_log_.IsLogging())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
- return WriteToEntry(kMetadataIndex, 0, NULL, 0, io_callback_);
-}
-
-int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoTruncateCachedMetadataComplete"));
-
- if (entry_) {
- if (net_log_.IsLogging()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
- result);
- }
- }
-
- next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
- return OK;
-}
-
-int HttpCache::Transaction::DoPartialHeadersReceived() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoPartialHeadersReceived"));
-
- new_response_ = NULL;
- if (entry_ && !partial_.get() &&
- entry_->disk_entry->GetDataSize(kMetadataIndex))
- next_state_ = STATE_CACHE_READ_METADATA;
-
- if (!partial_.get())
- return OK;
-
- if (reading_) {
- if (network_trans_.get()) {
- next_state_ = STATE_NETWORK_READ;
- } else {
- next_state_ = STATE_CACHE_READ_DATA;
- }
- } else if (mode_ != NONE) {
- // We are about to return the headers for a byte-range request to the user,
- // so let's fix them.
- partial_->FixResponseHeaders(response_.headers.get(), true);
- }
- return OK;
-}
-
-int HttpCache::Transaction::DoCacheReadResponse() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheReadResponse"));
-
- DCHECK(entry_);
- next_state_ = STATE_CACHE_READ_RESPONSE_COMPLETE;
-
- io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
- read_buf_ = new IOBuffer(io_buf_len_);
-
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
- return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(),
- io_buf_len_, io_callback_);
-}
-
-int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheReadResponseComplete"));
-
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
- if (result != io_buf_len_ ||
- !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_,
- &response_, &truncated_)) {
- return OnCacheReadError(result, true);
- }
-
- // cert_cache() will be null if the CertCacheTrial field trial is disabled.
- if (cache_->cert_cache() && response_.ssl_info.is_valid())
- ReadCertChain();
-
- // Some resources may have slipped in as truncated when they're not.
- int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
- if (response_.headers->GetContentLength() == current_size)
- truncated_ = false;
-
- if ((response_.unused_since_prefetch &&
- !(request_->load_flags & LOAD_PREFETCH)) ||
- (!response_.unused_since_prefetch &&
- (request_->load_flags & LOAD_PREFETCH))) {
- // Either this is the first use of an entry since it was prefetched or
- // this is a prefetch. The value of response.unused_since_prefetch is valid
- // for this transaction but the bit needs to be flipped in storage.
- next_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH;
- return OK;
- }
-
- next_state_ = STATE_CACHE_DISPATCH_VALIDATION;
- return OK;
-}
-
-int HttpCache::Transaction::DoCacheDispatchValidation() {
- // We now have access to the cache entry.
- //
- // o if we are a reader for the transaction, then we can start reading the
- // cache entry.
- //
- // o if we can read or write, then we should check if the cache entry needs
- // to be validated and then issue a network request if needed or just read
- // from the cache if the cache entry is already valid.
- //
- // o if we are set to UPDATE, then we are handling an externally
- // conditionalized request (if-modified-since / if-none-match). We check
- // if the request headers define a validation request.
- //
- int result = ERR_FAILED;
- switch (mode_) {
- case READ:
- UpdateTransactionPattern(PATTERN_ENTRY_USED);
- result = BeginCacheRead();
- break;
- case READ_WRITE:
- result = BeginPartialCacheValidation();
- break;
- case UPDATE:
- result = BeginExternallyConditionalizedRequest();
- break;
- case WRITE:
- default:
- NOTREACHED();
- }
- return result;
-}
-
-int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch() {
- // Write back the toggled value for the next use of this entry.
- response_.unused_since_prefetch = !response_.unused_since_prefetch;
-
- // TODO(jkarlin): If DoUpdateCachedResponse is also called for this
- // transaction then metadata will be written to cache twice. If prefetching
- // becomes more common, consider combining the writes.
- target_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE;
- next_state_ = STATE_CACHE_WRITE_RESPONSE;
- return OK;
-}
-
-int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetchComplete(
- int result) {
- // Restore the original value for this transaction.
- response_.unused_since_prefetch = !response_.unused_since_prefetch;
- next_state_ = STATE_CACHE_DISPATCH_VALIDATION;
- return OK;
-}
-
-int HttpCache::Transaction::DoCacheWriteResponse() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheWriteResponse"));
-
- if (entry_) {
- if (net_log_.IsLogging())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
- }
- return WriteResponseInfoToEntry(false);
-}
-
-int HttpCache::Transaction::DoCacheWriteTruncatedResponse() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheWriteTruncatedResponse"));
-
- if (entry_) {
- if (net_log_.IsLogging())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
- }
- return WriteResponseInfoToEntry(true);
-}
-
-int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheWriteResponseComplete"));
-
- next_state_ = target_state_;
- target_state_ = STATE_NONE;
- if (!entry_)
- return OK;
- if (net_log_.IsLogging()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
- result);
- }
-
- // Balance the AddRef from WriteResponseInfoToEntry.
- if (result != io_buf_len_) {
- DLOG(ERROR) << "failed to write response info to cache";
- DoneWritingToEntry(false);
- }
- return OK;
-}
-
-int HttpCache::Transaction::DoCacheReadMetadata() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheReadMetadata"));
-
- DCHECK(entry_);
- DCHECK(!response_.metadata.get());
- next_state_ = STATE_CACHE_READ_METADATA_COMPLETE;
-
- response_.metadata =
- new IOBufferWithSize(entry_->disk_entry->GetDataSize(kMetadataIndex));
-
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
- return entry_->disk_entry->ReadData(kMetadataIndex, 0,
- response_.metadata.get(),
- response_.metadata->size(),
- io_callback_);
-}
-
-int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheReadMetadataComplete"));
-
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
- if (result != response_.metadata->size())
- return OnCacheReadError(result, false);
- return OK;
-}
-
-int HttpCache::Transaction::DoCacheQueryData() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheQueryData"));
-
- next_state_ = STATE_CACHE_QUERY_DATA_COMPLETE;
- return entry_->disk_entry->ReadyForSparseIO(io_callback_);
-}
-
-int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheQueryDataComplete"));
-
- DCHECK_EQ(OK, result);
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- return ValidateEntryHeadersAndContinue();
-}
-
-int HttpCache::Transaction::DoCacheReadData() {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheReadData"));
-
- DCHECK(entry_);
- next_state_ = STATE_CACHE_READ_DATA_COMPLETE;
-
- if (net_log_.IsLogging())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA);
- if (partial_.get()) {
- return partial_->CacheRead(entry_->disk_entry, read_buf_.get(), io_buf_len_,
- io_callback_);
- }
-
- return entry_->disk_entry->ReadData(kResponseContentIndex, read_offset_,
- read_buf_.get(), io_buf_len_,
- io_callback_);
-}
-
-int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheReadDataComplete"));
-
- if (net_log_.IsLogging()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_DATA,
- result);
- }
-
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- if (partial_.get()) {
- // Partial requests are confusing to report in histograms because they may
- // have multiple underlying requests.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- return DoPartialCacheReadCompleted(result);
- }
-
- if (result > 0) {
- read_offset_ += result;
- } else if (result == 0) { // End of file.
- RecordHistograms();
- cache_->DoneReadingFromEntry(entry_, this);
- entry_ = NULL;
- } else {
- return OnCacheReadError(result, false);
- }
- return result;
-}
-
-int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheWriteData"));
-
- next_state_ = STATE_CACHE_WRITE_DATA_COMPLETE;
- write_len_ = num_bytes;
- if (entry_) {
- if (net_log_.IsLogging())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
- }
-
- return AppendResponseDataToEntry(read_buf_.get(), num_bytes, io_callback_);
-}
-
-int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422516 HttpCache::Transaction::DoCacheWriteDataComplete"));
-
- if (entry_) {
- if (net_log_.IsLogging()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
- result);
- }
- }
- // Balance the AddRef from DoCacheWriteData.
- if (!cache_.get())
- return ERR_UNEXPECTED;
-
- if (result != write_len_) {
- DLOG(ERROR) << "failed to write response data to cache";
- DoneWritingToEntry(false);
-
- // We want to ignore errors writing to disk and just keep reading from
- // the network.
- result = write_len_;
- } else if (!done_reading_ && entry_) {
- int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
- int64 body_size = response_.headers->GetContentLength();
- if (body_size >= 0 && body_size <= current_size)
- done_reading_ = true;
- }
-
- if (partial_.get()) {
- // This may be the last request.
- if (!(result == 0 && !truncated_ &&
- (partial_->IsLastRange() || mode_ == WRITE)))
- return DoPartialNetworkReadCompleted(result);
- }
-
- if (result == 0) {
- // End of file. This may be the result of a connection problem so see if we
- // have to keep the entry around to be flagged as truncated later on.
- if (done_reading_ || !entry_ || partial_.get() ||
- response_.headers->GetContentLength() <= 0)
- DoneWritingToEntry(true);
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-
-void HttpCache::Transaction::ReadCertChain() {
- std::string key =
- GetCacheKeyForCert(response_.ssl_info.cert->os_cert_handle());
- const X509Certificate::OSCertHandles& intermediates =
- response_.ssl_info.cert->GetIntermediateCertificates();
- int dist_from_root = intermediates.size();
-
- scoped_refptr<SharedChainData> shared_chain_data(
- new SharedChainData(intermediates.size() + 1, TimeTicks::Now()));
- cache_->cert_cache()->GetCertificate(key,
- base::Bind(&OnCertReadIOComplete,
- dist_from_root,
- true /* is leaf */,
- shared_chain_data));
-
- for (X509Certificate::OSCertHandles::const_iterator it =
- intermediates.begin();
- it != intermediates.end();
- ++it) {
- --dist_from_root;
- key = GetCacheKeyForCert(*it);
- cache_->cert_cache()->GetCertificate(key,
- base::Bind(&OnCertReadIOComplete,
- dist_from_root,
- false /* is not leaf */,
- shared_chain_data));
- }
- DCHECK_EQ(0, dist_from_root);
-}
-
-void HttpCache::Transaction::WriteCertChain() {
- const X509Certificate::OSCertHandles& intermediates =
- response_.ssl_info.cert->GetIntermediateCertificates();
- int dist_from_root = intermediates.size();
-
- scoped_refptr<SharedChainData> shared_chain_data(
- new SharedChainData(intermediates.size() + 1, TimeTicks::Now()));
- cache_->cert_cache()->SetCertificate(
- response_.ssl_info.cert->os_cert_handle(),
- base::Bind(&OnCertWriteIOComplete,
- dist_from_root,
- true /* is leaf */,
- shared_chain_data));
- for (X509Certificate::OSCertHandles::const_iterator it =
- intermediates.begin();
- it != intermediates.end();
- ++it) {
- --dist_from_root;
- cache_->cert_cache()->SetCertificate(*it,
- base::Bind(&OnCertWriteIOComplete,
- dist_from_root,
- false /* is not leaf */,
- shared_chain_data));
- }
- DCHECK_EQ(0, dist_from_root);
-}
-
-void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
- const HttpRequestInfo* request) {
- net_log_ = net_log;
- request_ = request;
- effective_load_flags_ = request_->load_flags;
-
- switch (cache_->mode()) {
- case NORMAL:
- break;
- case RECORD:
- // When in record mode, we want to NEVER load from the cache.
- // The reason for this is because we save the Set-Cookie headers
- // (intentionally). If we read from the cache, we replay them
- // prematurely.
- effective_load_flags_ |= LOAD_BYPASS_CACHE;
- break;
- case PLAYBACK:
- // When in playback mode, we want to load exclusively from the cache.
- effective_load_flags_ |= LOAD_ONLY_FROM_CACHE;
- break;
- case DISABLE:
- effective_load_flags_ |= LOAD_DISABLE_CACHE;
- break;
- }
-
- // Some headers imply load flags. The order here is significant.
- //
- // LOAD_DISABLE_CACHE : no cache read or write
- // LOAD_BYPASS_CACHE : no cache read
- // LOAD_VALIDATE_CACHE : no cache read unless validation
- //
- // The former modes trump latter modes, so if we find a matching header we
- // can stop iterating kSpecialHeaders.
- //
- static const struct {
- const HeaderNameAndValue* search;
- int load_flag;
- } kSpecialHeaders[] = {
- { kPassThroughHeaders, LOAD_DISABLE_CACHE },
- { kForceFetchHeaders, LOAD_BYPASS_CACHE },
- { kForceValidateHeaders, LOAD_VALIDATE_CACHE },
- };
-
- bool range_found = false;
- bool external_validation_error = false;
- bool special_headers = false;
-
- if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange))
- range_found = true;
-
- for (size_t i = 0; i < arraysize(kSpecialHeaders); ++i) {
- if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) {
- effective_load_flags_ |= kSpecialHeaders[i].load_flag;
- special_headers = true;
- break;
- }
- }
-
- // Check for conditionalization headers which may correspond with a
- // cache validation request.
- for (size_t i = 0; i < arraysize(kValidationHeaders); ++i) {
- const ValidationHeaderInfo& info = kValidationHeaders[i];
- std::string validation_value;
- if (request_->extra_headers.GetHeader(
- info.request_header_name, &validation_value)) {
- if (!external_validation_.values[i].empty() ||
- validation_value.empty()) {
- external_validation_error = true;
- }
- external_validation_.values[i] = validation_value;
- external_validation_.initialized = true;
- }
- }
-
- if (range_found || special_headers || external_validation_.initialized) {
- // Log the headers before request_ is modified.
- std::string empty;
- net_log_.AddEvent(
- NetLog::TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS,
- base::Bind(&HttpRequestHeaders::NetLogCallback,
- base::Unretained(&request_->extra_headers), &empty));
- }
-
- // We don't support ranges and validation headers.
- if (range_found && external_validation_.initialized) {
- LOG(WARNING) << "Byte ranges AND validation headers found.";
- effective_load_flags_ |= LOAD_DISABLE_CACHE;
- }
-
- // If there is more than one validation header, we can't treat this request as
- // a cache validation, since we don't know for sure which header the server
- // will give us a response for (and they could be contradictory).
- if (external_validation_error) {
- LOG(WARNING) << "Multiple or malformed validation headers found.";
- effective_load_flags_ |= LOAD_DISABLE_CACHE;
- }
-
- if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) {
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- partial_.reset(new PartialData);
- if (request_->method == "GET" && partial_->Init(request_->extra_headers)) {
- // We will be modifying the actual range requested to the server, so
- // let's remove the header here.
- custom_request_.reset(new HttpRequestInfo(*request_));
- custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange);
- request_ = custom_request_.get();
- partial_->SetHeaders(custom_request_->extra_headers);
- } else {
- // The range is invalid or we cannot handle it properly.
- VLOG(1) << "Invalid byte range found.";
- effective_load_flags_ |= LOAD_DISABLE_CACHE;
- partial_.reset(NULL);
- }
- }
-}
-
-bool HttpCache::Transaction::ShouldPassThrough() {
- // We may have a null disk_cache if there is an error we cannot recover from,
- // like not enough disk space, or sharing violations.
- if (!cache_->disk_cache_.get())
- return true;
-
- // When using the record/playback modes, we always use the cache
- // and we never pass through.
- if (cache_->mode() == RECORD || cache_->mode() == PLAYBACK)
- return false;
-
- if (effective_load_flags_ & LOAD_DISABLE_CACHE)
- return true;
-
- if (request_->method == "GET" || request_->method == "HEAD")
- return false;
-
- if (request_->method == "POST" && request_->upload_data_stream &&
- request_->upload_data_stream->identifier()) {
- return false;
- }
-
- if (request_->method == "PUT" && request_->upload_data_stream)
- return false;
-
- if (request_->method == "DELETE")
- return false;
-
- return true;
-}
-
-int HttpCache::Transaction::BeginCacheRead() {
- // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
- if (response_.headers->response_code() == 206 || partial_.get()) {
- NOTREACHED();
- return ERR_CACHE_MISS;
- }
-
- if (request_->method == "HEAD")
- FixHeadersForHead();
-
- // We don't have the whole resource.
- if (truncated_)
- return ERR_CACHE_MISS;
-
- if (entry_->disk_entry->GetDataSize(kMetadataIndex))
- next_state_ = STATE_CACHE_READ_METADATA;
-
- return OK;
-}
-
-int HttpCache::Transaction::BeginCacheValidation() {
- DCHECK(mode_ == READ_WRITE);
-
- ValidationType required_validation = RequiresValidation();
-
- bool skip_validation = (required_validation == VALIDATION_NONE);
-
- if (required_validation == VALIDATION_ASYNCHRONOUS &&
- !(request_->method == "GET" && (truncated_ || partial_)) && cache_ &&
- cache_->use_stale_while_revalidate()) {
- TriggerAsyncValidation();
- skip_validation = true;
- }
-
- if (request_->method == "HEAD" &&
- (truncated_ || response_.headers->response_code() == 206)) {
- DCHECK(!partial_);
- if (skip_validation)
- return SetupEntryForRead();
-
- // Bail out!
- next_state_ = STATE_SEND_REQUEST;
- mode_ = NONE;
- return OK;
- }
-
- if (truncated_) {
- // Truncated entries can cause partial gets, so we shouldn't record this
- // load in histograms.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- skip_validation = !partial_->initial_validation();
- }
-
- if (partial_.get() && (is_sparse_ || truncated_) &&
- (!partial_->IsCurrentRangeCached() || invalid_range_)) {
- // Force revalidation for sparse or truncated entries. Note that we don't
- // want to ignore the regular validation logic just because a byte range was
- // part of the request.
- skip_validation = false;
- }
-
- if (skip_validation) {
- // TODO(ricea): Is this pattern okay for asynchronous revalidations?
- UpdateTransactionPattern(PATTERN_ENTRY_USED);
- RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE);
- return SetupEntryForRead();
- } else {
- // Make the network request conditional, to see if we may reuse our cached
- // response. If we cannot do so, then we just resort to a normal fetch.
- // Our mode remains READ_WRITE for a conditional request. Even if the
- // conditionalization fails, we don't switch to WRITE mode until we
- // know we won't be falling back to using the cache entry in the
- // LOAD_FROM_CACHE_IF_OFFLINE case.
- if (!ConditionalizeRequest()) {
- couldnt_conditionalize_request_ = true;
- UpdateTransactionPattern(PATTERN_ENTRY_CANT_CONDITIONALIZE);
- if (partial_.get())
- return DoRestartPartialRequest();
-
- DCHECK_NE(206, response_.headers->response_code());
- }
- next_state_ = STATE_SEND_REQUEST;
- }
- return OK;
-}
-
-int HttpCache::Transaction::BeginPartialCacheValidation() {
- DCHECK(mode_ == READ_WRITE);
-
- if (response_.headers->response_code() != 206 && !partial_.get() &&
- !truncated_) {
- return BeginCacheValidation();
- }
-
- // Partial requests should not be recorded in histograms.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- if (range_requested_) {
- next_state_ = STATE_CACHE_QUERY_DATA;
- return OK;
- }
-
- // The request is not for a range, but we have stored just ranges.
-
- if (request_->method == "HEAD")
- return BeginCacheValidation();
-
- partial_.reset(new PartialData());
- partial_->SetHeaders(request_->extra_headers);
- if (!custom_request_.get()) {
- custom_request_.reset(new HttpRequestInfo(*request_));
- request_ = custom_request_.get();
- }
-
- return ValidateEntryHeadersAndContinue();
-}
-
-// This should only be called once per request.
-int HttpCache::Transaction::ValidateEntryHeadersAndContinue() {
- DCHECK(mode_ == READ_WRITE);
-
- if (!partial_->UpdateFromStoredHeaders(
- response_.headers.get(), entry_->disk_entry, truncated_)) {
- return DoRestartPartialRequest();
- }
-
- if (response_.headers->response_code() == 206)
- is_sparse_ = true;
-
- if (!partial_->IsRequestedRangeOK()) {
- // The stored data is fine, but the request may be invalid.
- invalid_range_ = true;
- }
-
- next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
- return OK;
-}
-
-int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
- DCHECK_EQ(UPDATE, mode_);
- DCHECK(external_validation_.initialized);
-
- for (size_t i = 0; i < arraysize(kValidationHeaders); i++) {
- if (external_validation_.values[i].empty())
- continue;
- // Retrieve either the cached response's "etag" or "last-modified" header.
- std::string validator;
- response_.headers->EnumerateHeader(
- NULL,
- kValidationHeaders[i].related_response_header_name,
- &validator);
-
- if (response_.headers->response_code() != 200 || truncated_ ||
- validator.empty() || validator != external_validation_.values[i]) {
- // The externally conditionalized request is not a validation request
- // for our existing cache entry. Proceed with caching disabled.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- DoneWritingToEntry(true);
- }
- }
-
- // TODO(ricea): This calculation is expensive to perform just to collect
- // statistics. Either remove it or use the result, depending on the result of
- // the experiment.
- ExternallyConditionalizedType type =
- EXTERNALLY_CONDITIONALIZED_CACHE_USABLE;
- if (mode_ == NONE)
- type = EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS;
- else if (RequiresValidation())
- type = EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION;
-
- // TODO(ricea): Add CACHE_USABLE_STALE once stale-while-revalidate CL landed.
- // TODO(ricea): Either remove this histogram or make it permanent by M40.
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ExternallyConditionalized",
- type,
- EXTERNALLY_CONDITIONALIZED_MAX);
-
- next_state_ = STATE_SEND_REQUEST;
- return OK;
-}
-
-int HttpCache::Transaction::RestartNetworkRequest() {
- DCHECK(mode_ & WRITE || mode_ == NONE);
- DCHECK(network_trans_.get());
- DCHECK_EQ(STATE_NONE, next_state_);
-
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
- int rv = network_trans_->RestartIgnoringLastError(io_callback_);
- if (rv != ERR_IO_PENDING)
- return DoLoop(rv);
- return rv;
-}
-
-int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
- X509Certificate* client_cert) {
- DCHECK(mode_ & WRITE || mode_ == NONE);
- DCHECK(network_trans_.get());
- DCHECK_EQ(STATE_NONE, next_state_);
-
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
- int rv = network_trans_->RestartWithCertificate(client_cert, io_callback_);
- if (rv != ERR_IO_PENDING)
- return DoLoop(rv);
- return rv;
-}
-
-int HttpCache::Transaction::RestartNetworkRequestWithAuth(
- const AuthCredentials& credentials) {
- DCHECK(mode_ & WRITE || mode_ == NONE);
- DCHECK(network_trans_.get());
- DCHECK_EQ(STATE_NONE, next_state_);
-
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
- int rv = network_trans_->RestartWithAuth(credentials, io_callback_);
- if (rv != ERR_IO_PENDING)
- return DoLoop(rv);
- return rv;
-}
-
-ValidationType HttpCache::Transaction::RequiresValidation() {
- // TODO(darin): need to do more work here:
- // - make sure we have a matching request method
- // - watch out for cached responses that depend on authentication
-
- // In playback mode, nothing requires validation.
- if (cache_->mode() == net::HttpCache::PLAYBACK)
- return VALIDATION_NONE;
-
- if (response_.vary_data.is_valid() &&
- !response_.vary_data.MatchesRequest(*request_,
- *response_.headers.get())) {
- vary_mismatch_ = true;
- return VALIDATION_SYNCHRONOUS;
- }
-
- if (effective_load_flags_ & LOAD_PREFERRING_CACHE)
- return VALIDATION_NONE;
-
- if (response_.unused_since_prefetch &&
- !(effective_load_flags_ & LOAD_PREFETCH) &&
- response_.headers->GetCurrentAge(
- response_.request_time, response_.response_time,
- cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) {
- // The first use of a resource after prefetch within a short window skips
- // validation.
- return VALIDATION_NONE;
- }
-
- if (effective_load_flags_ & (LOAD_VALIDATE_CACHE | LOAD_ASYNC_REVALIDATION))
- return VALIDATION_SYNCHRONOUS;
-
- if (request_->method == "PUT" || request_->method == "DELETE")
- return VALIDATION_SYNCHRONOUS;
-
- ValidationType validation_required_by_headers =
- response_.headers->RequiresValidation(response_.request_time,
- response_.response_time,
- cache_->clock_->Now());
-
- if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) {
- // Asynchronous revalidation is only supported for GET and HEAD methods.
- if (request_->method != "GET" && request_->method != "HEAD")
- return VALIDATION_SYNCHRONOUS;
- }
-
- return validation_required_by_headers;
-}
-
-bool HttpCache::Transaction::ConditionalizeRequest() {
- DCHECK(response_.headers.get());
-
- if (request_->method == "PUT" || request_->method == "DELETE")
- return false;
-
- // This only makes sense for cached 200 or 206 responses.
- if (response_.headers->response_code() != 200 &&
- response_.headers->response_code() != 206) {
- return false;
- }
-
- if (fail_conditionalization_for_test_)
- return false;
-
- DCHECK(response_.headers->response_code() != 206 ||
- response_.headers->HasStrongValidators());
-
- // Just use the first available ETag and/or Last-Modified header value.
- // TODO(darin): Or should we use the last?
-
- std::string etag_value;
- if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1))
- response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
-
- std::string last_modified_value;
- if (!vary_mismatch_) {
- response_.headers->EnumerateHeader(NULL, "last-modified",
- &last_modified_value);
- }
-
- if (etag_value.empty() && last_modified_value.empty())
- return false;
-
- if (!partial_.get()) {
- // Need to customize the request, so this forces us to allocate :(
- custom_request_.reset(new HttpRequestInfo(*request_));
- request_ = custom_request_.get();
- }
- DCHECK(custom_request_.get());
-
- bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() &&
- !invalid_range_;
-
- if (!use_if_range) {
- // stale-while-revalidate is not useful when we only have a partial response
- // cached, so don't set the header in that case.
- HttpResponseHeaders::FreshnessLifetimes lifetimes =
- response_.headers->GetFreshnessLifetimes(response_.response_time);
- if (lifetimes.staleness > TimeDelta()) {
- TimeDelta current_age = response_.headers->GetCurrentAge(
- response_.request_time, response_.response_time,
- cache_->clock_->Now());
-
- custom_request_->extra_headers.SetHeader(
- kFreshnessHeader,
- base::StringPrintf("max-age=%" PRId64
- ",stale-while-revalidate=%" PRId64 ",age=%" PRId64,
- lifetimes.freshness.InSeconds(),
- lifetimes.staleness.InSeconds(),
- current_age.InSeconds()));
- }
- }
-
- if (!etag_value.empty()) {
- if (use_if_range) {
- // We don't want to switch to WRITE mode if we don't have this block of a
- // byte-range request because we may have other parts cached.
- custom_request_->extra_headers.SetHeader(
- HttpRequestHeaders::kIfRange, etag_value);
- } else {
- custom_request_->extra_headers.SetHeader(
- HttpRequestHeaders::kIfNoneMatch, etag_value);
- }
- // For byte-range requests, make sure that we use only one way to validate
- // the request.
- if (partial_.get() && !partial_->IsCurrentRangeCached())
- return true;
- }
-
- if (!last_modified_value.empty()) {
- if (use_if_range) {
- custom_request_->extra_headers.SetHeader(
- HttpRequestHeaders::kIfRange, last_modified_value);
- } else {
- custom_request_->extra_headers.SetHeader(
- HttpRequestHeaders::kIfModifiedSince, last_modified_value);
- }
- }
-
- return true;
-}
-
-// We just received some headers from the server. We may have asked for a range,
-// in which case partial_ has an object. This could be the first network request
-// we make to fulfill the original request, or we may be already reading (from
-// the net and / or the cache). If we are not expecting a certain response, we
-// just bypass the cache for this request (but again, maybe we are reading), and
-// delete partial_ (so we are not able to "fix" the headers that we return to
-// the user). This results in either a weird response for the caller (we don't
-// expect it after all), or maybe a range that was not exactly what it was asked
-// for.
-//
-// If the server is simply telling us that the resource has changed, we delete
-// the cached entry and restart the request as the caller intended (by returning
-// false from this method). However, we may not be able to do that at any point,
-// for instance if we already returned the headers to the user.
-//
-// WARNING: Whenever this code returns false, it has to make sure that the next
-// time it is called it will return true so that we don't keep retrying the
-// request.
-bool HttpCache::Transaction::ValidatePartialResponse() {
- const HttpResponseHeaders* headers = new_response_->headers.get();
- int response_code = headers->response_code();
- bool partial_response = (response_code == 206);
- handling_206_ = false;
-
- if (!entry_ || request_->method != "GET")
- return true;
-
- if (invalid_range_) {
- // We gave up trying to match this request with the stored data. If the
- // server is ok with the request, delete the entry, otherwise just ignore
- // this request
- DCHECK(!reading_);
- if (partial_response || response_code == 200) {
- DoomPartialEntry(true);
- mode_ = NONE;
- } else {
- if (response_code == 304)
- FailRangeRequest();
- IgnoreRangeRequest();
- }
- return true;
- }
-
- if (!partial_.get()) {
- // We are not expecting 206 but we may have one.
- if (partial_response)
- IgnoreRangeRequest();
-
- return true;
- }
-
- // TODO(rvargas): Do we need to consider other results here?.
- bool failure = response_code == 200 || response_code == 416;
-
- if (partial_->IsCurrentRangeCached()) {
- // We asked for "If-None-Match: " so a 206 means a new object.
- if (partial_response)
- failure = true;
-
- if (response_code == 304 && partial_->ResponseHeadersOK(headers))
- return true;
- } else {
- // We asked for "If-Range: " so a 206 means just another range.
- if (partial_response) {
- if (partial_->ResponseHeadersOK(headers)) {
- handling_206_ = true;
- return true;
- } else {
- failure = true;
- }
- }
-
- if (!reading_ && !is_sparse_ && !partial_response) {
- // See if we can ignore the fact that we issued a byte range request.
- // If the server sends 200, just store it. If it sends an error, redirect
- // or something else, we may store the response as long as we didn't have
- // anything already stored.
- if (response_code == 200 ||
- (!truncated_ && response_code != 304 && response_code != 416)) {
- // The server is sending something else, and we can save it.
- DCHECK((truncated_ && !partial_->IsLastRange()) || range_requested_);
- partial_.reset();
- truncated_ = false;
- return true;
- }
- }
-
- // 304 is not expected here, but we'll spare the entry (unless it was
- // truncated).
- if (truncated_)
- failure = true;
- }
-
- if (failure) {
- // We cannot truncate this entry, it has to be deleted.
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- mode_ = NONE;
- if (is_sparse_ || truncated_) {
- // There was something cached to start with, either sparsed data (206), or
- // a truncated 200, which means that we probably modified the request,
- // adding a byte range or modifying the range requested by the caller.
- if (!reading_ && !partial_->IsLastRange()) {
- // We have not returned anything to the caller yet so it should be safe
- // to issue another network request, this time without us messing up the
- // headers.
- ResetPartialState(true);
- return false;
- }
- LOG(WARNING) << "Failed to revalidate partial entry";
- }
- DoomPartialEntry(true);
- return true;
- }
-
- IgnoreRangeRequest();
- return true;
-}
-
-void HttpCache::Transaction::IgnoreRangeRequest() {
- // We have a problem. We may or may not be reading already (in which case we
- // returned the headers), but we'll just pretend that this request is not
- // using the cache and see what happens. Most likely this is the first
- // response from the server (it's not changing its mind midway, right?).
- UpdateTransactionPattern(PATTERN_NOT_COVERED);
- if (mode_ & WRITE)
- DoneWritingToEntry(mode_ != WRITE);
- else if (mode_ & READ && entry_)
- cache_->DoneReadingFromEntry(entry_, this);
-
- partial_.reset(NULL);
- entry_ = NULL;
- mode_ = NONE;
-}
-
-void HttpCache::Transaction::FixHeadersForHead() {
- if (response_.headers->response_code() == 206) {
- response_.headers->RemoveHeader("Content-Range");
- response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK");
- }
-}
-
-void HttpCache::Transaction::TriggerAsyncValidation() {
- DCHECK(!request_->upload_data_stream);
- BoundNetLog async_revalidation_net_log(
- BoundNetLog::Make(net_log_.net_log(), NetLog::SOURCE_ASYNC_REVALIDATION));
- net_log_.AddEvent(
- NetLog::TYPE_HTTP_CACHE_VALIDATE_RESOURCE_ASYNC,
- async_revalidation_net_log.source().ToEventParametersCallback());
- async_revalidation_net_log.BeginEvent(
- NetLog::TYPE_ASYNC_REVALIDATION,
- base::Bind(
- &NetLogAsyncRevalidationInfoCallback, net_log_.source(), request_));
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&HttpCache::PerformAsyncValidation,
- cache_, // cache_ is a weak pointer.
- *request_,
- async_revalidation_net_log));
-}
-
-void HttpCache::Transaction::FailRangeRequest() {
- response_ = *new_response_;
- partial_->FixResponseHeaders(response_.headers.get(), false);
-}
-
-int HttpCache::Transaction::SetupEntryForRead() {
- if (network_trans_)
- ResetNetworkTransaction();
- if (partial_.get()) {
- if (truncated_ || is_sparse_ || !invalid_range_) {
- // We are going to return the saved response headers to the caller, so
- // we may need to adjust them first.
- next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
- return OK;
- } else {
- partial_.reset();
- }
- }
- cache_->ConvertWriterToReader(entry_);
- mode_ = READ;
-
- if (request_->method == "HEAD")
- FixHeadersForHead();
-
- if (entry_->disk_entry->GetDataSize(kMetadataIndex))
- next_state_ = STATE_CACHE_READ_METADATA;
- return OK;
-}
-
-
-int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) {
- read_buf_ = data;
- io_buf_len_ = data_len;
- next_state_ = STATE_NETWORK_READ;
- return DoLoop(OK);
-}
-
-int HttpCache::Transaction::ReadFromEntry(IOBuffer* data, int data_len) {
- if (request_->method == "HEAD")
- return 0;
-
- read_buf_ = data;
- io_buf_len_ = data_len;
- next_state_ = STATE_CACHE_READ_DATA;
- return DoLoop(OK);
-}
-
-int HttpCache::Transaction::WriteToEntry(int index, int offset,
- IOBuffer* data, int data_len,
- const CompletionCallback& callback) {
- if (!entry_)
- return data_len;
-
- int rv = 0;
- if (!partial_.get() || !data_len) {
- rv = entry_->disk_entry->WriteData(index, offset, data, data_len, callback,
- true);
- } else {
- rv = partial_->CacheWrite(entry_->disk_entry, data, data_len, callback);
- }
- return rv;
-}
-
-int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
- next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE;
- if (!entry_)
- return OK;
-
- // Do not cache no-store content (unless we are record mode). Do not cache
- // content with cert errors either. This is to prevent not reporting net
- // errors when loading a resource from the cache. When we load a page over
- // HTTPS with a cert error we show an SSL blocking page. If the user clicks
- // proceed we reload the resource ignoring the errors. The loaded resource
- // is then cached. If that resource is subsequently loaded from the cache,
- // no net error is reported (even though the cert status contains the actual
- // errors) and no SSL blocking page is shown. An alternative would be to
- // reverse-map the cert status to a net error and replay the net error.
- if ((cache_->mode() != RECORD &&
- response_.headers->HasHeaderValue("cache-control", "no-store")) ||
- net::IsCertStatusError(response_.ssl_info.cert_status)) {
- DoneWritingToEntry(false);
- if (net_log_.IsLogging())
- net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
- return OK;
- }
-
- // cert_cache() will be null if the CertCacheTrial field trial is disabled.
- if (cache_->cert_cache() && response_.ssl_info.is_valid())
- WriteCertChain();
-
- // When writing headers, we normally only write the non-transient
- // headers; when in record mode, record everything.
- bool skip_transient_headers = (cache_->mode() != RECORD);
-
- if (truncated)
- DCHECK_EQ(200, response_.headers->response_code());
-
- scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer());
- response_.Persist(data->pickle(), skip_transient_headers, truncated);
- data->Done();
-
- io_buf_len_ = data->pickle()->size();
- return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
- io_buf_len_, io_callback_, true);
-}
-
-int HttpCache::Transaction::AppendResponseDataToEntry(
- IOBuffer* data, int data_len, const CompletionCallback& callback) {
- if (!entry_ || !data_len)
- return data_len;
-
- int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
- return WriteToEntry(kResponseContentIndex, current_size, data, data_len,
- callback);
-}
-
-void HttpCache::Transaction::DoneWritingToEntry(bool success) {
- if (!entry_)
- return;
-
- RecordHistograms();
-
- cache_->DoneWritingToEntry(entry_, success);
- entry_ = NULL;
- mode_ = NONE; // switch to 'pass through' mode
-}
-
-int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
- DLOG(ERROR) << "ReadData failed: " << result;
- const int result_for_histogram = std::max(0, -result);
- if (restart) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("HttpCache.ReadErrorRestartable",
- result_for_histogram);
- } else {
- UMA_HISTOGRAM_SPARSE_SLOWLY("HttpCache.ReadErrorNonRestartable",
- result_for_histogram);
- }
-
- // Avoid using this entry in the future.
- if (cache_.get())
- cache_->DoomActiveEntry(cache_key_);
-
- if (restart) {
- DCHECK(!reading_);
- DCHECK(!network_trans_.get());
- cache_->DoneWithEntry(entry_, this, false);
- entry_ = NULL;
- is_sparse_ = false;
- partial_.reset();
- next_state_ = STATE_GET_BACKEND;
- return OK;
- }
-
- return ERR_CACHE_READ_FAILURE;
-}
-
-void HttpCache::Transaction::OnAddToEntryTimeout(base::TimeTicks start_time) {
- if (entry_lock_waiting_since_ != start_time)
- return;
-
- DCHECK_EQ(next_state_, STATE_ADD_TO_ENTRY_COMPLETE);
-
- if (!cache_)
- return;
-
- cache_->RemovePendingTransaction(this);
- OnIOComplete(ERR_CACHE_LOCK_TIMEOUT);
-}
-
-void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
- DVLOG(2) << "DoomPartialEntry";
- int rv = cache_->DoomEntry(cache_key_, NULL);
- DCHECK_EQ(OK, rv);
- cache_->DoneWithEntry(entry_, this, false);
- entry_ = NULL;
- is_sparse_ = false;
- truncated_ = false;
- if (delete_object)
- partial_.reset(NULL);
-}
-
-int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
- partial_->OnNetworkReadCompleted(result);
-
- if (result == 0) {
- // We need to move on to the next range.
- ResetNetworkTransaction();
- next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
- }
- return result;
-}
-
-int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
- partial_->OnCacheReadCompleted(result);
-
- if (result == 0 && mode_ == READ_WRITE) {
- // We need to move on to the next range.
- next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
- } else if (result < 0) {
- return OnCacheReadError(result, false);
- }
- return result;
-}
-
-int HttpCache::Transaction::DoRestartPartialRequest() {
- // The stored data cannot be used. Get rid of it and restart this request.
- net_log_.AddEvent(NetLog::TYPE_HTTP_CACHE_RESTART_PARTIAL_REQUEST);
-
- // WRITE + Doom + STATE_INIT_ENTRY == STATE_CREATE_ENTRY (without an attempt
- // to Doom the entry again).
- mode_ = WRITE;
- ResetPartialState(!range_requested_);
- next_state_ = STATE_CREATE_ENTRY;
- return OK;
-}
-
-void HttpCache::Transaction::ResetPartialState(bool delete_object) {
- partial_->RestoreHeaders(&custom_request_->extra_headers);
- DoomPartialEntry(delete_object);
-
- if (!delete_object) {
- // The simplest way to re-initialize partial_ is to create a new object.
- partial_.reset(new PartialData());
- if (partial_->Init(request_->extra_headers))
- partial_->SetHeaders(custom_request_->extra_headers);
- else
- partial_.reset();
- }
-}
-
-void HttpCache::Transaction::ResetNetworkTransaction() {
- DCHECK(!old_network_trans_load_timing_);
- DCHECK(network_trans_);
- LoadTimingInfo load_timing;
- if (network_trans_->GetLoadTimingInfo(&load_timing))
- old_network_trans_load_timing_.reset(new LoadTimingInfo(load_timing));
- total_received_bytes_ += network_trans_->GetTotalReceivedBytes();
- network_trans_.reset();
-}
-
-// Histogram data from the end of 2010 show the following distribution of
-// response headers:
-//
-// Content-Length............... 87%
-// Date......................... 98%
-// Last-Modified................ 49%
-// Etag......................... 19%
-// Accept-Ranges: bytes......... 25%
-// Accept-Ranges: none.......... 0.4%
-// Strong Validator............. 50%
-// Strong Validator + ranges.... 24%
-// Strong Validator + CL........ 49%
-//
-bool HttpCache::Transaction::CanResume(bool has_data) {
- // Double check that there is something worth keeping.
- if (has_data && !entry_->disk_entry->GetDataSize(kResponseContentIndex))
- return false;
-
- if (request_->method != "GET")
- return false;
-
- // Note that if this is a 206, content-length was already fixed after calling
- // PartialData::ResponseHeadersOK().
- if (response_.headers->GetContentLength() <= 0 ||
- response_.headers->HasHeaderValue("Accept-Ranges", "none") ||
- !response_.headers->HasStrongValidators()) {
- return false;
- }
-
- return true;
-}
-
-void HttpCache::Transaction::UpdateTransactionPattern(
- TransactionPattern new_transaction_pattern) {
- if (transaction_pattern_ == PATTERN_NOT_COVERED)
- return;
- DCHECK(transaction_pattern_ == PATTERN_UNDEFINED ||
- new_transaction_pattern == PATTERN_NOT_COVERED);
- transaction_pattern_ = new_transaction_pattern;
-}
-
-void HttpCache::Transaction::RecordHistograms() {
- DCHECK_NE(PATTERN_UNDEFINED, transaction_pattern_);
- if (!cache_.get() || !cache_->GetCurrentBackend() ||
- cache_->GetCurrentBackend()->GetCacheType() != DISK_CACHE ||
- cache_->mode() != NORMAL || request_->method != "GET") {
- return;
- }
- UMA_HISTOGRAM_ENUMERATION(
- "HttpCache.Pattern", transaction_pattern_, PATTERN_MAX);
- if (transaction_pattern_ == PATTERN_NOT_COVERED)
- return;
- DCHECK(!range_requested_);
- DCHECK(!first_cache_access_since_.is_null());
-
- TimeDelta total_time = base::TimeTicks::Now() - first_cache_access_since_;
-
- UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone", total_time);
-
- bool did_send_request = !send_request_since_.is_null();
- DCHECK(
- (did_send_request &&
- (transaction_pattern_ == PATTERN_ENTRY_NOT_CACHED ||
- transaction_pattern_ == PATTERN_ENTRY_VALIDATED ||
- transaction_pattern_ == PATTERN_ENTRY_UPDATED ||
- transaction_pattern_ == PATTERN_ENTRY_CANT_CONDITIONALIZE)) ||
- (!did_send_request && transaction_pattern_ == PATTERN_ENTRY_USED));
-
- if (!did_send_request) {
- DCHECK(transaction_pattern_ == PATTERN_ENTRY_USED);
- UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.Used", total_time);
- return;
- }
-
- TimeDelta before_send_time = send_request_since_ - first_cache_access_since_;
- int64 before_send_percent = (total_time.ToInternalValue() == 0) ?
- 0 : before_send_time * 100 / total_time;
- DCHECK_GE(before_send_percent, 0);
- DCHECK_LE(before_send_percent, 100);
- base::HistogramBase::Sample before_send_sample =
- static_cast<base::HistogramBase::Sample>(before_send_percent);
-
- UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SentRequest", total_time);
- UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend", before_send_time);
- UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend", before_send_sample);
-
- // TODO(gavinp): Remove or minimize these histograms, particularly the ones
- // below this comment after we have received initial data.
- switch (transaction_pattern_) {
- case PATTERN_ENTRY_CANT_CONDITIONALIZE: {
- UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.CantConditionalize",
- before_send_time);
- UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.CantConditionalize",
- before_send_sample);
- break;
- }
- case PATTERN_ENTRY_NOT_CACHED: {
- UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.NotCached", before_send_time);
- UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.NotCached",
- before_send_sample);
- break;
- }
- case PATTERN_ENTRY_VALIDATED: {
- UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Validated", before_send_time);
- UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.Validated",
- before_send_sample);
- break;
- }
- case PATTERN_ENTRY_UPDATED: {
- UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Updated", before_send_time);
- UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.Updated",
- before_send_sample);
- break;
- }
- default:
- NOTREACHED();
- }
-}
-
-void HttpCache::Transaction::OnIOComplete(int result) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 Transaction::OnIOComplete"));
-
- DoLoop(result);
-}
-
-} // namespace net
« no previous file with comments | « net/http/http_cache_transaction.h ('k') | net/http/http_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698