OLD | NEW |
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 Loading... |
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_TIMES("DiskBasedCertCache.ChainReadTime", read_chain_wait); |
| 102 } |
| 103 |
| 104 bool success = (cert_handle != NULL); |
| 105 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessTotal", success); |
| 106 |
| 107 if (is_leaf) |
| 108 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessLeaf", success); |
| 109 else if (dist_from_root == 0) |
| 110 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessRoot", success); |
| 111 else if (dist_from_root == 1) |
| 112 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessInt1", success); |
| 113 else if (dist_from_root == 2) |
| 114 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessInt2", success); |
| 115 else |
| 116 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.ReadSuccessIntN", success); |
| 117 } |
| 118 |
| 119 // |dist_from_root| indicates the position of the written certificate in the |
| 120 // certificate chain, 0 indicating it is the root. |is_leaf| indicates |
| 121 // whether or not the written certificate was the leaf of the chain. |
| 122 // |shared_chain_data| contains data shared by each certificate in |
| 123 // the chain. |
| 124 void OnCertWriteIOComplete( |
| 125 int dist_from_root, |
| 126 bool is_leaf, |
| 127 const scoped_refptr<SharedChainData>& shared_chain_data, |
| 128 const std::string& key) { |
| 129 // If |num_pending_ops| is one, this was the last pending write operation |
| 130 // for this chain of certificates. The total time used to write the chain |
| 131 // can be calculated by subtracting the starting time from Now(). |
| 132 shared_chain_data->num_pending_ops--; |
| 133 if (!shared_chain_data->num_pending_ops) { |
| 134 const TimeDelta write_chain_wait = |
| 135 TimeTicks::Now() - shared_chain_data->start_time; |
| 136 UMA_HISTOGRAM_TIMES("DiskBasedCertCache.ChainWriteTime", write_chain_wait); |
| 137 } |
| 138 |
| 139 bool success = !key.empty(); |
| 140 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessTotal", success); |
| 141 |
| 142 if (is_leaf) |
| 143 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessLeaf", success); |
| 144 else if (dist_from_root == 0) |
| 145 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessRoot", success); |
| 146 else if (dist_from_root == 1) |
| 147 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessInt1", success); |
| 148 else if (dist_from_root == 2) |
| 149 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessInt2", success); |
| 150 else |
| 151 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.WriteSuccessIntN", success); |
| 152 } |
| 153 |
50 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6 | 154 // 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 | 155 // a "non-error response" is one with a 2xx (Successful) or 3xx |
52 // (Redirection) status code. | 156 // (Redirection) status code. |
53 bool NonErrorResponse(int status_code) { | 157 bool NonErrorResponse(int status_code) { |
54 int status_code_range = status_code / 100; | 158 int status_code_range = status_code / 100; |
55 return status_code_range == 2 || status_code_range == 3; | 159 return status_code_range == 2 || status_code_range == 3; |
56 } | 160 } |
57 | 161 |
58 // Error codes that will be considered indicative of a page being offline/ | 162 // Error codes that will be considered indicative of a page being offline/ |
59 // unreachable for LOAD_FROM_CACHE_IF_OFFLINE. | 163 // unreachable for LOAD_FROM_CACHE_IF_OFFLINE. |
(...skipping 1428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1488 } | 1592 } |
1489 | 1593 |
1490 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { | 1594 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { |
1491 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); | 1595 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); |
1492 if (result != io_buf_len_ || | 1596 if (result != io_buf_len_ || |
1493 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, | 1597 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, |
1494 &response_, &truncated_)) { | 1598 &response_, &truncated_)) { |
1495 return OnCacheReadError(result, true); | 1599 return OnCacheReadError(result, true); |
1496 } | 1600 } |
1497 | 1601 |
| 1602 // cert_cache() will be null if the CertCacheTrial field trial is disabled. |
| 1603 if (cache_->cert_cache() && response_.ssl_info.is_valid()) |
| 1604 CertChainRead(); |
| 1605 |
1498 // Some resources may have slipped in as truncated when they're not. | 1606 // Some resources may have slipped in as truncated when they're not. |
1499 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); | 1607 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); |
1500 if (response_.headers->GetContentLength() == current_size) | 1608 if (response_.headers->GetContentLength() == current_size) |
1501 truncated_ = false; | 1609 truncated_ = false; |
1502 | 1610 |
1503 // We now have access to the cache entry. | 1611 // We now have access to the cache entry. |
1504 // | 1612 // |
1505 // o if we are a reader for the transaction, then we can start reading the | 1613 // o if we are a reader for the transaction, then we can start reading the |
1506 // cache entry. | 1614 // cache entry. |
1507 // | 1615 // |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1700 if (done_reading_ || !entry_ || partial_.get() || | 1808 if (done_reading_ || !entry_ || partial_.get() || |
1701 response_.headers->GetContentLength() <= 0) | 1809 response_.headers->GetContentLength() <= 0) |
1702 DoneWritingToEntry(true); | 1810 DoneWritingToEntry(true); |
1703 } | 1811 } |
1704 | 1812 |
1705 return result; | 1813 return result; |
1706 } | 1814 } |
1707 | 1815 |
1708 //----------------------------------------------------------------------------- | 1816 //----------------------------------------------------------------------------- |
1709 | 1817 |
| 1818 void HttpCache::Transaction::CertChainRead() { |
| 1819 std::string key = |
| 1820 GetCacheKeyForCert(response_.ssl_info.cert->os_cert_handle()); |
| 1821 const X509Certificate::OSCertHandles& intermediates = |
| 1822 response_.ssl_info.cert->GetIntermediateCertificates(); |
| 1823 int dist_from_root = intermediates.size(); |
| 1824 |
| 1825 scoped_refptr<SharedChainData> shared_chain_data( |
| 1826 new SharedChainData(intermediates.size() + 1, TimeTicks::Now())); |
| 1827 cache_->cert_cache()->Get(key, |
| 1828 base::Bind(&OnCertReadIOComplete, |
| 1829 dist_from_root, |
| 1830 true /* is leaf */, |
| 1831 shared_chain_data)); |
| 1832 |
| 1833 for (X509Certificate::OSCertHandles::const_iterator it = |
| 1834 intermediates.begin(); |
| 1835 it != intermediates.end(); |
| 1836 ++it) { |
| 1837 --dist_from_root; |
| 1838 key = GetCacheKeyForCert(*it); |
| 1839 cache_->cert_cache()->Get(key, |
| 1840 base::Bind(&OnCertReadIOComplete, |
| 1841 dist_from_root, |
| 1842 false /* is not leaf */, |
| 1843 shared_chain_data)); |
| 1844 } |
| 1845 DCHECK_EQ(0, dist_from_root); |
| 1846 } |
| 1847 |
| 1848 void HttpCache::Transaction::CertChainWrite() { |
| 1849 const X509Certificate::OSCertHandles& intermediates = |
| 1850 response_.ssl_info.cert->GetIntermediateCertificates(); |
| 1851 int dist_from_root = intermediates.size(); |
| 1852 |
| 1853 scoped_refptr<SharedChainData> shared_chain_data( |
| 1854 new SharedChainData(intermediates.size() + 1, TimeTicks::Now())); |
| 1855 cache_->cert_cache()->Set(response_.ssl_info.cert->os_cert_handle(), |
| 1856 base::Bind(&OnCertWriteIOComplete, |
| 1857 dist_from_root, |
| 1858 true /* is leaf */, |
| 1859 shared_chain_data)); |
| 1860 for (X509Certificate::OSCertHandles::const_iterator it = |
| 1861 intermediates.begin(); |
| 1862 it != intermediates.end(); |
| 1863 ++it) { |
| 1864 --dist_from_root; |
| 1865 cache_->cert_cache()->Set(*it, |
| 1866 base::Bind(&OnCertWriteIOComplete, |
| 1867 dist_from_root, |
| 1868 false /* is not leaf */, |
| 1869 shared_chain_data)); |
| 1870 } |
| 1871 DCHECK_EQ(0, dist_from_root); |
| 1872 } |
| 1873 |
1710 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, | 1874 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, |
1711 const HttpRequestInfo* request) { | 1875 const HttpRequestInfo* request) { |
1712 net_log_ = net_log; | 1876 net_log_ = net_log; |
1713 request_ = request; | 1877 request_ = request; |
1714 effective_load_flags_ = request_->load_flags; | 1878 effective_load_flags_ = request_->load_flags; |
1715 | 1879 |
1716 switch (cache_->mode()) { | 1880 switch (cache_->mode()) { |
1717 case NORMAL: | 1881 case NORMAL: |
1718 break; | 1882 break; |
1719 case RECORD: | 1883 case RECORD: |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2320 // reverse-map the cert status to a net error and replay the net error. | 2484 // reverse-map the cert status to a net error and replay the net error. |
2321 if ((cache_->mode() != RECORD && | 2485 if ((cache_->mode() != RECORD && |
2322 response_.headers->HasHeaderValue("cache-control", "no-store")) || | 2486 response_.headers->HasHeaderValue("cache-control", "no-store")) || |
2323 net::IsCertStatusError(response_.ssl_info.cert_status)) { | 2487 net::IsCertStatusError(response_.ssl_info.cert_status)) { |
2324 DoneWritingToEntry(false); | 2488 DoneWritingToEntry(false); |
2325 if (net_log_.IsLogging()) | 2489 if (net_log_.IsLogging()) |
2326 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); | 2490 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); |
2327 return OK; | 2491 return OK; |
2328 } | 2492 } |
2329 | 2493 |
| 2494 // cert_cache() will be null if the CertCacheTrial field trial is disabled. |
| 2495 if (cache_->cert_cache() && response_.ssl_info.is_valid()) |
| 2496 CertChainWrite(); |
| 2497 |
2330 // When writing headers, we normally only write the non-transient | 2498 // When writing headers, we normally only write the non-transient |
2331 // headers; when in record mode, record everything. | 2499 // headers; when in record mode, record everything. |
2332 bool skip_transient_headers = (cache_->mode() != RECORD); | 2500 bool skip_transient_headers = (cache_->mode() != RECORD); |
2333 | 2501 |
2334 if (truncated) | 2502 if (truncated) |
2335 DCHECK_EQ(200, response_.headers->response_code()); | 2503 DCHECK_EQ(200, response_.headers->response_code()); |
2336 | 2504 |
2337 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); | 2505 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
2338 response_.Persist(data->pickle(), skip_transient_headers, truncated); | 2506 response_.Persist(data->pickle(), skip_transient_headers, truncated); |
2339 data->Done(); | 2507 data->Done(); |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2576 default: | 2744 default: |
2577 NOTREACHED(); | 2745 NOTREACHED(); |
2578 } | 2746 } |
2579 } | 2747 } |
2580 | 2748 |
2581 void HttpCache::Transaction::OnIOComplete(int result) { | 2749 void HttpCache::Transaction::OnIOComplete(int result) { |
2582 DoLoop(result); | 2750 DoLoop(result); |
2583 } | 2751 } |
2584 | 2752 |
2585 } // namespace net | 2753 } // namespace net |
OLD | NEW |