| Index: net/http/http_cache_transaction.cc
|
| diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
|
| index bf791118be88b704966c7d3a886d5fcc4c924f63..8a2b0ecb2805cd93102a2ae37936196a33c7eb80 100644
|
| --- a/net/http/http_cache_transaction.cc
|
| +++ b/net/http/http_cache_transaction.cc
|
| @@ -32,6 +32,7 @@
|
| #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"
|
| @@ -47,6 +48,109 @@ using base::TimeTicks;
|
|
|
| namespace {
|
|
|
| +// 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_TIMES("DiskBasedCertCache.ChainReadTime", read_chain_wait);
|
| + }
|
| +
|
| + bool success = (cert_handle != NULL);
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessTotal", success);
|
| +
|
| + if (is_leaf)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessLeaf", success);
|
| + else if (dist_from_root == 0)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessRoot", success);
|
| + else if (dist_from_root == 1)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessInt1", success);
|
| + else if (dist_from_root == 2)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessInt2", success);
|
| + else
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessIntN", success);
|
| +}
|
| +
|
| +// |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_TIMES("DiskBasedCertCache.ChainWriteTime", write_chain_wait);
|
| + }
|
| +
|
| + bool success = !key.empty();
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessTotal", success);
|
| +
|
| + if (is_leaf)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessLeaf", success);
|
| + else if (dist_from_root == 0)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessRoot", success);
|
| + else if (dist_from_root == 1)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessInt1", success);
|
| + else if (dist_from_root == 2)
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessInt2", success);
|
| + else
|
| + UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessIntN", success);
|
| +}
|
| +
|
| // 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.
|
| @@ -1495,6 +1599,10 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
|
| 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())
|
| + CertChainRead();
|
| +
|
| // 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)
|
| @@ -1707,6 +1815,62 @@ int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
|
|
|
| //-----------------------------------------------------------------------------
|
|
|
| +void HttpCache::Transaction::CertChainRead() {
|
| + 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()->Get(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()->Get(key,
|
| + base::Bind(&OnCertReadIOComplete,
|
| + dist_from_root,
|
| + false /* is not leaf */,
|
| + shared_chain_data));
|
| + }
|
| + DCHECK_EQ(0, dist_from_root);
|
| +}
|
| +
|
| +void HttpCache::Transaction::CertChainWrite() {
|
| + 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()->Set(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()->Set(*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;
|
| @@ -2327,6 +2491,10 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
|
| return OK;
|
| }
|
|
|
| + // cert_cache() will be null if the CertCacheTrial field trial is disabled.
|
| + if (cache_->cert_cache() && response_.ssl_info.is_valid())
|
| + CertChainWrite();
|
| +
|
| // When writing headers, we normally only write the non-transient
|
| // headers; when in record mode, record everything.
|
| bool skip_transient_headers = (cache_->mode() != RECORD);
|
|
|