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

Side by Side Diff: net/http/http_cache_transaction.cc

Issue 356953003: Adding DiskBasedCertCache to HttpCache (+UMA). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@current
Patch Set: Fixed issues (remembered to compile). Created 6 years, 5 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_cache_transaction.h" 5 #include "net/http/http_cache_transaction.h"
6 6
7 #include "build/build_config.h" 7 #include "build/build_config.h"
8 8
9 #if defined(OS_POSIX) 9 #if defined(OS_POSIX)
10 #include <unistd.h> 10 #include <unistd.h>
(...skipping 14 matching lines...) Expand all
25 #include "base/time/time.h" 25 #include "base/time/time.h"
26 #include "net/base/completion_callback.h" 26 #include "net/base/completion_callback.h"
27 #include "net/base/io_buffer.h" 27 #include "net/base/io_buffer.h"
28 #include "net/base/load_flags.h" 28 #include "net/base/load_flags.h"
29 #include "net/base/load_timing_info.h" 29 #include "net/base/load_timing_info.h"
30 #include "net/base/net_errors.h" 30 #include "net/base/net_errors.h"
31 #include "net/base/net_log.h" 31 #include "net/base/net_log.h"
32 #include "net/base/upload_data_stream.h" 32 #include "net/base/upload_data_stream.h"
33 #include "net/cert/cert_status_flags.h" 33 #include "net/cert/cert_status_flags.h"
34 #include "net/disk_cache/disk_cache.h" 34 #include "net/disk_cache/disk_cache.h"
35 #include "net/http/disk_based_cert_cache.h"
35 #include "net/http/http_network_session.h" 36 #include "net/http/http_network_session.h"
36 #include "net/http/http_request_info.h" 37 #include "net/http/http_request_info.h"
37 #include "net/http/http_response_headers.h" 38 #include "net/http/http_response_headers.h"
38 #include "net/http/http_transaction.h" 39 #include "net/http/http_transaction.h"
39 #include "net/http/http_util.h" 40 #include "net/http/http_util.h"
40 #include "net/http/partial_data.h" 41 #include "net/http/partial_data.h"
41 #include "net/ssl/ssl_cert_request_info.h" 42 #include "net/ssl/ssl_cert_request_info.h"
42 #include "net/ssl/ssl_config_service.h" 43 #include "net/ssl/ssl_config_service.h"
43 44
44 using base::Time; 45 using base::Time;
45 using base::TimeDelta; 46 using base::TimeDelta;
46 using base::TimeTicks; 47 using base::TimeTicks;
47 48
48 namespace { 49 namespace {
49 50
51 // Stores data relevant to the statistics of writing and reading entire
52 // certificate chains using DiskBasedCertCache. |num_pending_ops| is the number
53 // of certificates in the chain that have pending operations in the
54 // DiskBasedCertCache. |start_time| is the time that the read and write
55 // commands began being issued to the DiskBasedCertCache.
56 // TODO(brandonsalmon): Remove this when it is no longer necessary to
57 // collect data.
58 class SharedChainData : public base::RefCounted<SharedChainData> {
59 public:
60 SharedChainData(int num_ops, TimeTicks start)
61 : num_pending_ops(num_ops), start_time(start) {}
62
63 int num_pending_ops;
64 TimeTicks start_time;
65
66 private:
67 friend class base::RefCounted<SharedChainData>;
68 ~SharedChainData() {}
69 DISALLOW_COPY_AND_ASSIGN(SharedChainData);
70 };
71
72 // Used to obtain a cache entry key for an OSCertHandle.
73 // TODO(brandonsalmon): Remove this when cache keys are stored
74 // and no longer have to be recomputed to retrieve the OSCertHandle
75 // from the disk.
76 std::string GetCacheKeyForCert(net::X509Certificate::OSCertHandle cert_handle) {
77 net::SHA1HashValue fingerprint =
78 net::X509Certificate::CalculateFingerprint(cert_handle);
79
80 return "cert:" +
81 base::HexEncode(fingerprint.data, arraysize(fingerprint.data));
82 }
83
84 // |dist_from_root| indicates the position of the read certificate in the
85 // certificate chain, 0 indicating it is the root. |is_leaf| indicates
86 // whether or not the read certificate was the leaf of the chain.
87 // |shared_chain_data| contains data shared by each certificate in
88 // the chain.
89 void OnCertReadIOComplete(
90 int dist_from_root,
91 bool is_leaf,
92 const scoped_refptr<SharedChainData>& shared_chain_data,
93 net::X509Certificate::OSCertHandle cert_handle) {
94 // If |num_pending_ops| is one, this was the last pending read operation
95 // for this chain of certificates. The total time used to read the chain
96 // can be calculated by subtracting the starting time from Now().
97 shared_chain_data->num_pending_ops--;
98 if (!shared_chain_data->num_pending_ops) {
99 const TimeDelta read_chain_wait =
100 TimeTicks::Now() - shared_chain_data->start_time;
101 UMA_HISTOGRAM_CUSTOM_TIMES("DiskBasedCertCache.ChainReadTime",
wtc 2014/07/10 18:42:21 Should this histogram name also use the "CertIo" p
brandonsalmon 2014/07/10 19:00:13 It was my intention that "Chain" would become a di
102 read_chain_wait,
103 base::TimeDelta::FromMilliseconds(1),
104 base::TimeDelta::FromMinutes(10),
105 50);
106 }
107
108 bool success = (cert_handle != NULL);
109 if (is_leaf)
110 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.CertIoReadSuccessLeaf", success);
wtc 2014/07/10 18:42:21 IMPORTANT: should we return here? Otherwise the re
brandonsalmon 2014/07/10 19:00:13 I did this because it didn't make sense to me to r
111
112 if (success)
113 UMA_HISTOGRAM_CUSTOM_COUNTS(
114 "DiskBasedCertCache.CertIoReadSuccess", dist_from_root, 0, 10, 7);
115 else
116 UMA_HISTOGRAM_CUSTOM_COUNTS(
117 "DiskBasedCertCache.CertIoReadFailure", dist_from_root, 0, 10, 7);
wtc 2014/07/10 18:42:21 Nit: use curly braces because the bodies of the if
118 }
119
120 // |dist_from_root| indicates the position of the written certificate in the
121 // certificate chain, 0 indicating it is the root. |is_leaf| indicates
122 // whether or not the written certificate was the leaf of the chain.
123 // |shared_chain_data| contains data shared by each certificate in
124 // the chain.
125 void OnCertWriteIOComplete(
126 int dist_from_root,
127 bool is_leaf,
128 const scoped_refptr<SharedChainData>& shared_chain_data,
129 const std::string& key) {
130 // If |num_pending_ops| is one, this was the last pending write operation
131 // for this chain of certificates. The total time used to write the chain
132 // can be calculated by subtracting the starting time from Now().
133 shared_chain_data->num_pending_ops--;
134 if (!shared_chain_data->num_pending_ops) {
135 const TimeDelta write_chain_wait =
136 TimeTicks::Now() - shared_chain_data->start_time;
137 UMA_HISTOGRAM_CUSTOM_TIMES("DiskBasedCertCache.ChainWriteTime",
138 write_chain_wait,
139 base::TimeDelta::FromMilliseconds(1),
140 base::TimeDelta::FromMinutes(10),
141 50);
142 }
143
144 bool success = !key.empty();
145 if (is_leaf)
146 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.CertIoWriteSuccessLeaf", success);
147
148 if (success)
149 UMA_HISTOGRAM_CUSTOM_COUNTS(
150 "DiskBasedCertCache.CertIoWriteSuccess", dist_from_root, 0, 10, 7);
151 else
152 UMA_HISTOGRAM_CUSTOM_COUNTS(
153 "DiskBasedCertCache.CertIoWriteFailure", dist_from_root, 0, 10, 7);
154 }
155
50 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6 156 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6
51 // a "non-error response" is one with a 2xx (Successful) or 3xx 157 // a "non-error response" is one with a 2xx (Successful) or 3xx
52 // (Redirection) status code. 158 // (Redirection) status code.
53 bool NonErrorResponse(int status_code) { 159 bool NonErrorResponse(int status_code) {
54 int status_code_range = status_code / 100; 160 int status_code_range = status_code / 100;
55 return status_code_range == 2 || status_code_range == 3; 161 return status_code_range == 2 || status_code_range == 3;
56 } 162 }
57 163
58 // Error codes that will be considered indicative of a page being offline/ 164 // Error codes that will be considered indicative of a page being offline/
59 // unreachable for LOAD_FROM_CACHE_IF_OFFLINE. 165 // unreachable for LOAD_FROM_CACHE_IF_OFFLINE.
(...skipping 1428 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 } 1594 }
1489 1595
1490 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { 1596 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
1491 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); 1597 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
1492 if (result != io_buf_len_ || 1598 if (result != io_buf_len_ ||
1493 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, 1599 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_,
1494 &response_, &truncated_)) { 1600 &response_, &truncated_)) {
1495 return OnCacheReadError(result, true); 1601 return OnCacheReadError(result, true);
1496 } 1602 }
1497 1603
1604 // cert_cache() will be null if the CertCacheTrial field trial is disabled.
1605 if (cache_->cert_cache() && response_.ssl_info.is_valid())
1606 ReadCertChain();
1607
1498 // Some resources may have slipped in as truncated when they're not. 1608 // Some resources may have slipped in as truncated when they're not.
1499 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); 1609 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
1500 if (response_.headers->GetContentLength() == current_size) 1610 if (response_.headers->GetContentLength() == current_size)
1501 truncated_ = false; 1611 truncated_ = false;
1502 1612
1503 // We now have access to the cache entry. 1613 // We now have access to the cache entry.
1504 // 1614 //
1505 // o if we are a reader for the transaction, then we can start reading the 1615 // o if we are a reader for the transaction, then we can start reading the
1506 // cache entry. 1616 // cache entry.
1507 // 1617 //
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1700 if (done_reading_ || !entry_ || partial_.get() || 1810 if (done_reading_ || !entry_ || partial_.get() ||
1701 response_.headers->GetContentLength() <= 0) 1811 response_.headers->GetContentLength() <= 0)
1702 DoneWritingToEntry(true); 1812 DoneWritingToEntry(true);
1703 } 1813 }
1704 1814
1705 return result; 1815 return result;
1706 } 1816 }
1707 1817
1708 //----------------------------------------------------------------------------- 1818 //-----------------------------------------------------------------------------
1709 1819
1820 void HttpCache::Transaction::ReadCertChain() {
1821 std::string key =
1822 GetCacheKeyForCert(response_.ssl_info.cert->os_cert_handle());
1823 const X509Certificate::OSCertHandles& intermediates =
1824 response_.ssl_info.cert->GetIntermediateCertificates();
1825 int dist_from_root = intermediates.size();
1826
1827 scoped_refptr<SharedChainData> shared_chain_data(
1828 new SharedChainData(intermediates.size() + 1, TimeTicks::Now()));
1829 cache_->cert_cache()->Get(key,
1830 base::Bind(&OnCertReadIOComplete,
1831 dist_from_root,
1832 true /* is leaf */,
1833 shared_chain_data));
1834
1835 for (X509Certificate::OSCertHandles::const_iterator it =
1836 intermediates.begin();
1837 it != intermediates.end();
1838 ++it) {
1839 --dist_from_root;
1840 key = GetCacheKeyForCert(*it);
1841 cache_->cert_cache()->Get(key,
1842 base::Bind(&OnCertReadIOComplete,
1843 dist_from_root,
1844 false /* is not leaf */,
1845 shared_chain_data));
1846 }
1847 DCHECK_EQ(0, dist_from_root);
1848 }
1849
1850 void HttpCache::Transaction::WriteCertChain() {
1851 const X509Certificate::OSCertHandles& intermediates =
1852 response_.ssl_info.cert->GetIntermediateCertificates();
1853 int dist_from_root = intermediates.size();
1854
1855 scoped_refptr<SharedChainData> shared_chain_data(
1856 new SharedChainData(intermediates.size() + 1, TimeTicks::Now()));
1857 cache_->cert_cache()->Set(response_.ssl_info.cert->os_cert_handle(),
1858 base::Bind(&OnCertWriteIOComplete,
1859 dist_from_root,
1860 true /* is leaf */,
1861 shared_chain_data));
1862 for (X509Certificate::OSCertHandles::const_iterator it =
1863 intermediates.begin();
1864 it != intermediates.end();
1865 ++it) {
1866 --dist_from_root;
1867 cache_->cert_cache()->Set(*it,
1868 base::Bind(&OnCertWriteIOComplete,
1869 dist_from_root,
1870 false /* is not leaf */,
1871 shared_chain_data));
1872 }
1873 DCHECK_EQ(0, dist_from_root);
1874 }
1875
1710 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, 1876 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
1711 const HttpRequestInfo* request) { 1877 const HttpRequestInfo* request) {
1712 net_log_ = net_log; 1878 net_log_ = net_log;
1713 request_ = request; 1879 request_ = request;
1714 effective_load_flags_ = request_->load_flags; 1880 effective_load_flags_ = request_->load_flags;
1715 1881
1716 switch (cache_->mode()) { 1882 switch (cache_->mode()) {
1717 case NORMAL: 1883 case NORMAL:
1718 break; 1884 break;
1719 case RECORD: 1885 case RECORD:
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
2320 // reverse-map the cert status to a net error and replay the net error. 2486 // reverse-map the cert status to a net error and replay the net error.
2321 if ((cache_->mode() != RECORD && 2487 if ((cache_->mode() != RECORD &&
2322 response_.headers->HasHeaderValue("cache-control", "no-store")) || 2488 response_.headers->HasHeaderValue("cache-control", "no-store")) ||
2323 net::IsCertStatusError(response_.ssl_info.cert_status)) { 2489 net::IsCertStatusError(response_.ssl_info.cert_status)) {
2324 DoneWritingToEntry(false); 2490 DoneWritingToEntry(false);
2325 if (net_log_.IsLogging()) 2491 if (net_log_.IsLogging())
2326 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); 2492 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
2327 return OK; 2493 return OK;
2328 } 2494 }
2329 2495
2496 // cert_cache() will be null if the CertCacheTrial field trial is disabled.
2497 if (cache_->cert_cache() && response_.ssl_info.is_valid())
2498 WriteCertChain();
2499
2330 // When writing headers, we normally only write the non-transient 2500 // When writing headers, we normally only write the non-transient
2331 // headers; when in record mode, record everything. 2501 // headers; when in record mode, record everything.
2332 bool skip_transient_headers = (cache_->mode() != RECORD); 2502 bool skip_transient_headers = (cache_->mode() != RECORD);
2333 2503
2334 if (truncated) 2504 if (truncated)
2335 DCHECK_EQ(200, response_.headers->response_code()); 2505 DCHECK_EQ(200, response_.headers->response_code());
2336 2506
2337 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); 2507 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer());
2338 response_.Persist(data->pickle(), skip_transient_headers, truncated); 2508 response_.Persist(data->pickle(), skip_transient_headers, truncated);
2339 data->Done(); 2509 data->Done();
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
2576 default: 2746 default:
2577 NOTREACHED(); 2747 NOTREACHED();
2578 } 2748 }
2579 } 2749 }
2580 2750
2581 void HttpCache::Transaction::OnIOComplete(int result) { 2751 void HttpCache::Transaction::OnIOComplete(int result) {
2582 DoLoop(result); 2752 DoLoop(result);
2583 } 2753 }
2584 2754
2585 } // namespace net 2755 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698