| 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" // For OS_POSIX | 7 #include "build/build_config.h" // For OS_POSIX |
| 8 | 8 |
| 9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 #include "base/thread_task_runner_handle.h" | 29 #include "base/thread_task_runner_handle.h" |
| 30 #include "base/time/clock.h" | 30 #include "base/time/clock.h" |
| 31 #include "base/values.h" | 31 #include "base/values.h" |
| 32 #include "net/base/auth.h" | 32 #include "net/base/auth.h" |
| 33 #include "net/base/load_flags.h" | 33 #include "net/base/load_flags.h" |
| 34 #include "net/base/load_timing_info.h" | 34 #include "net/base/load_timing_info.h" |
| 35 #include "net/base/upload_data_stream.h" | 35 #include "net/base/upload_data_stream.h" |
| 36 #include "net/cert/cert_status_flags.h" | 36 #include "net/cert/cert_status_flags.h" |
| 37 #include "net/cert/x509_certificate.h" | 37 #include "net/cert/x509_certificate.h" |
| 38 #include "net/disk_cache/disk_cache.h" | 38 #include "net/disk_cache/disk_cache.h" |
| 39 #include "net/http/disk_based_cert_cache.h" | |
| 40 #include "net/http/http_network_session.h" | 39 #include "net/http/http_network_session.h" |
| 41 #include "net/http/http_request_info.h" | 40 #include "net/http/http_request_info.h" |
| 42 #include "net/http/http_util.h" | 41 #include "net/http/http_util.h" |
| 43 #include "net/ssl/ssl_cert_request_info.h" | 42 #include "net/ssl/ssl_cert_request_info.h" |
| 44 #include "net/ssl/ssl_config_service.h" | 43 #include "net/ssl/ssl_config_service.h" |
| 45 | 44 |
| 46 using base::Time; | 45 using base::Time; |
| 47 using base::TimeDelta; | 46 using base::TimeDelta; |
| 48 using base::TimeTicks; | 47 using base::TimeTicks; |
| 49 | 48 |
| 50 namespace net { | 49 namespace net { |
| 51 | 50 |
| 52 namespace { | 51 namespace { |
| 53 | 52 |
| 54 // TODO(ricea): Move this to HttpResponseHeaders once it is standardised. | 53 // TODO(ricea): Move this to HttpResponseHeaders once it is standardised. |
| 55 static const char kFreshnessHeader[] = "Resource-Freshness"; | 54 static const char kFreshnessHeader[] = "Resource-Freshness"; |
| 56 | 55 |
| 57 // Stores data relevant to the statistics of writing and reading entire | |
| 58 // certificate chains using DiskBasedCertCache. |num_pending_ops| is the number | |
| 59 // of certificates in the chain that have pending operations in the | |
| 60 // DiskBasedCertCache. |start_time| is the time that the read and write | |
| 61 // commands began being issued to the DiskBasedCertCache. | |
| 62 // TODO(brandonsalmon): Remove this when it is no longer necessary to | |
| 63 // collect data. | |
| 64 class SharedChainData : public base::RefCounted<SharedChainData> { | |
| 65 public: | |
| 66 SharedChainData(int num_ops, TimeTicks start) | |
| 67 : num_pending_ops(num_ops), start_time(start) {} | |
| 68 | |
| 69 int num_pending_ops; | |
| 70 TimeTicks start_time; | |
| 71 | |
| 72 private: | |
| 73 friend class base::RefCounted<SharedChainData>; | |
| 74 ~SharedChainData() {} | |
| 75 DISALLOW_COPY_AND_ASSIGN(SharedChainData); | |
| 76 }; | |
| 77 | |
| 78 // Used to obtain a cache entry key for an OSCertHandle. | |
| 79 // TODO(brandonsalmon): Remove this when cache keys are stored | |
| 80 // and no longer have to be recomputed to retrieve the OSCertHandle | |
| 81 // from the disk. | |
| 82 std::string GetCacheKeyForCert(X509Certificate::OSCertHandle cert_handle) { | |
| 83 SHA1HashValue fingerprint = | |
| 84 X509Certificate::CalculateFingerprint(cert_handle); | |
| 85 | |
| 86 return "cert:" + | |
| 87 base::HexEncode(fingerprint.data, arraysize(fingerprint.data)); | |
| 88 } | |
| 89 | |
| 90 // |dist_from_root| indicates the position of the read certificate in the | |
| 91 // certificate chain, 0 indicating it is the root. |is_leaf| indicates | |
| 92 // whether or not the read certificate was the leaf of the chain. | |
| 93 // |shared_chain_data| contains data shared by each certificate in | |
| 94 // the chain. | |
| 95 void OnCertReadIOComplete( | |
| 96 int dist_from_root, | |
| 97 bool is_leaf, | |
| 98 const scoped_refptr<SharedChainData>& shared_chain_data, | |
| 99 X509Certificate::OSCertHandle cert_handle) { | |
| 100 // If |num_pending_ops| is one, this was the last pending read operation | |
| 101 // for this chain of certificates. The total time used to read the chain | |
| 102 // can be calculated by subtracting the starting time from Now(). | |
| 103 shared_chain_data->num_pending_ops--; | |
| 104 if (!shared_chain_data->num_pending_ops) { | |
| 105 const TimeDelta read_chain_wait = | |
| 106 TimeTicks::Now() - shared_chain_data->start_time; | |
| 107 UMA_HISTOGRAM_CUSTOM_TIMES("DiskBasedCertCache.ChainReadTime", | |
| 108 read_chain_wait, | |
| 109 base::TimeDelta::FromMilliseconds(1), | |
| 110 base::TimeDelta::FromMinutes(10), | |
| 111 50); | |
| 112 } | |
| 113 | |
| 114 bool success = (cert_handle != NULL); | |
| 115 if (is_leaf) | |
| 116 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.CertIoReadSuccessLeaf", success); | |
| 117 | |
| 118 if (success) | |
| 119 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
| 120 "DiskBasedCertCache.CertIoReadSuccess", dist_from_root, 0, 10, 7); | |
| 121 else | |
| 122 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
| 123 "DiskBasedCertCache.CertIoReadFailure", dist_from_root, 0, 10, 7); | |
| 124 } | |
| 125 | |
| 126 // |dist_from_root| indicates the position of the written certificate in the | |
| 127 // certificate chain, 0 indicating it is the root. |is_leaf| indicates | |
| 128 // whether or not the written certificate was the leaf of the chain. | |
| 129 // |shared_chain_data| contains data shared by each certificate in | |
| 130 // the chain. | |
| 131 void OnCertWriteIOComplete( | |
| 132 int dist_from_root, | |
| 133 bool is_leaf, | |
| 134 const scoped_refptr<SharedChainData>& shared_chain_data, | |
| 135 const std::string& key) { | |
| 136 // If |num_pending_ops| is one, this was the last pending write operation | |
| 137 // for this chain of certificates. The total time used to write the chain | |
| 138 // can be calculated by subtracting the starting time from Now(). | |
| 139 shared_chain_data->num_pending_ops--; | |
| 140 if (!shared_chain_data->num_pending_ops) { | |
| 141 const TimeDelta write_chain_wait = | |
| 142 TimeTicks::Now() - shared_chain_data->start_time; | |
| 143 UMA_HISTOGRAM_CUSTOM_TIMES("DiskBasedCertCache.ChainWriteTime", | |
| 144 write_chain_wait, | |
| 145 base::TimeDelta::FromMilliseconds(1), | |
| 146 base::TimeDelta::FromMinutes(10), | |
| 147 50); | |
| 148 } | |
| 149 | |
| 150 bool success = !key.empty(); | |
| 151 if (is_leaf) | |
| 152 UMA_HISTOGRAM_BOOLEAN("DiskBasedCertCache.CertIoWriteSuccessLeaf", success); | |
| 153 | |
| 154 if (success) | |
| 155 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
| 156 "DiskBasedCertCache.CertIoWriteSuccess", dist_from_root, 0, 10, 7); | |
| 157 else | |
| 158 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
| 159 "DiskBasedCertCache.CertIoWriteFailure", dist_from_root, 0, 10, 7); | |
| 160 } | |
| 161 | |
| 162 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6 | 56 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6 |
| 163 // a "non-error response" is one with a 2xx (Successful) or 3xx | 57 // a "non-error response" is one with a 2xx (Successful) or 3xx |
| 164 // (Redirection) status code. | 58 // (Redirection) status code. |
| 165 bool NonErrorResponse(int status_code) { | 59 bool NonErrorResponse(int status_code) { |
| 166 int status_code_range = status_code / 100; | 60 int status_code_range = status_code / 100; |
| 167 return status_code_range == 2 || status_code_range == 3; | 61 return status_code_range == 2 || status_code_range == 3; |
| 168 } | 62 } |
| 169 | 63 |
| 170 void RecordNoStoreHeaderHistogram(int load_flags, | 64 void RecordNoStoreHeaderHistogram(int load_flags, |
| 171 const HttpResponseInfo* response) { | 65 const HttpResponseInfo* response) { |
| (...skipping 1097 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1269 } | 1163 } |
| 1270 | 1164 |
| 1271 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { | 1165 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { |
| 1272 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); | 1166 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); |
| 1273 if (result != io_buf_len_ || | 1167 if (result != io_buf_len_ || |
| 1274 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, &response_, | 1168 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, &response_, |
| 1275 &truncated_)) { | 1169 &truncated_)) { |
| 1276 return OnCacheReadError(result, true); | 1170 return OnCacheReadError(result, true); |
| 1277 } | 1171 } |
| 1278 | 1172 |
| 1279 // cert_cache() will be null if the CertCacheTrial field trial is disabled. | |
| 1280 if (cache_->cert_cache() && response_.ssl_info.is_valid()) | |
| 1281 ReadCertChain(); | |
| 1282 | |
| 1283 // Some resources may have slipped in as truncated when they're not. | 1173 // Some resources may have slipped in as truncated when they're not. |
| 1284 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); | 1174 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); |
| 1285 if (response_.headers->GetContentLength() == current_size) | 1175 if (response_.headers->GetContentLength() == current_size) |
| 1286 truncated_ = false; | 1176 truncated_ = false; |
| 1287 | 1177 |
| 1288 if ((response_.unused_since_prefetch && | 1178 if ((response_.unused_since_prefetch && |
| 1289 !(request_->load_flags & LOAD_PREFETCH)) || | 1179 !(request_->load_flags & LOAD_PREFETCH)) || |
| 1290 (!response_.unused_since_prefetch && | 1180 (!response_.unused_since_prefetch && |
| 1291 (request_->load_flags & LOAD_PREFETCH))) { | 1181 (request_->load_flags & LOAD_PREFETCH))) { |
| 1292 // Either this is the first use of an entry since it was prefetched or | 1182 // Either this is the first use of an entry since it was prefetched or |
| (...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1912 next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE; | 1802 next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE_COMPLETE; |
| 1913 return WriteResponseInfoToEntry(true); | 1803 return WriteResponseInfoToEntry(true); |
| 1914 } | 1804 } |
| 1915 | 1805 |
| 1916 int HttpCache::Transaction::DoCacheWriteTruncatedResponseComplete(int result) { | 1806 int HttpCache::Transaction::DoCacheWriteTruncatedResponseComplete(int result) { |
| 1917 return OnWriteResponseInfoToEntryComplete(result); | 1807 return OnWriteResponseInfoToEntryComplete(result); |
| 1918 } | 1808 } |
| 1919 | 1809 |
| 1920 //----------------------------------------------------------------------------- | 1810 //----------------------------------------------------------------------------- |
| 1921 | 1811 |
| 1922 void HttpCache::Transaction::ReadCertChain() { | |
| 1923 std::string key = | |
| 1924 GetCacheKeyForCert(response_.ssl_info.cert->os_cert_handle()); | |
| 1925 const X509Certificate::OSCertHandles& intermediates = | |
| 1926 response_.ssl_info.cert->GetIntermediateCertificates(); | |
| 1927 int dist_from_root = intermediates.size(); | |
| 1928 | |
| 1929 scoped_refptr<SharedChainData> shared_chain_data( | |
| 1930 new SharedChainData(intermediates.size() + 1, TimeTicks::Now())); | |
| 1931 cache_->cert_cache()->GetCertificate(key, | |
| 1932 base::Bind(&OnCertReadIOComplete, | |
| 1933 dist_from_root, | |
| 1934 true /* is leaf */, | |
| 1935 shared_chain_data)); | |
| 1936 | |
| 1937 for (X509Certificate::OSCertHandles::const_iterator it = | |
| 1938 intermediates.begin(); | |
| 1939 it != intermediates.end(); | |
| 1940 ++it) { | |
| 1941 --dist_from_root; | |
| 1942 key = GetCacheKeyForCert(*it); | |
| 1943 cache_->cert_cache()->GetCertificate(key, | |
| 1944 base::Bind(&OnCertReadIOComplete, | |
| 1945 dist_from_root, | |
| 1946 false /* is not leaf */, | |
| 1947 shared_chain_data)); | |
| 1948 } | |
| 1949 DCHECK_EQ(0, dist_from_root); | |
| 1950 } | |
| 1951 | |
| 1952 void HttpCache::Transaction::WriteCertChain() { | |
| 1953 const X509Certificate::OSCertHandles& intermediates = | |
| 1954 response_.ssl_info.cert->GetIntermediateCertificates(); | |
| 1955 int dist_from_root = intermediates.size(); | |
| 1956 | |
| 1957 scoped_refptr<SharedChainData> shared_chain_data( | |
| 1958 new SharedChainData(intermediates.size() + 1, TimeTicks::Now())); | |
| 1959 cache_->cert_cache()->SetCertificate( | |
| 1960 response_.ssl_info.cert->os_cert_handle(), | |
| 1961 base::Bind(&OnCertWriteIOComplete, | |
| 1962 dist_from_root, | |
| 1963 true /* is leaf */, | |
| 1964 shared_chain_data)); | |
| 1965 for (X509Certificate::OSCertHandles::const_iterator it = | |
| 1966 intermediates.begin(); | |
| 1967 it != intermediates.end(); | |
| 1968 ++it) { | |
| 1969 --dist_from_root; | |
| 1970 cache_->cert_cache()->SetCertificate(*it, | |
| 1971 base::Bind(&OnCertWriteIOComplete, | |
| 1972 dist_from_root, | |
| 1973 false /* is not leaf */, | |
| 1974 shared_chain_data)); | |
| 1975 } | |
| 1976 DCHECK_EQ(0, dist_from_root); | |
| 1977 } | |
| 1978 | |
| 1979 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, | 1812 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, |
| 1980 const HttpRequestInfo* request) { | 1813 const HttpRequestInfo* request) { |
| 1981 net_log_ = net_log; | 1814 net_log_ = net_log; |
| 1982 request_ = request; | 1815 request_ = request; |
| 1983 effective_load_flags_ = request_->load_flags; | 1816 effective_load_flags_ = request_->load_flags; |
| 1984 | 1817 |
| 1985 if (cache_->mode() == DISABLE) | 1818 if (cache_->mode() == DISABLE) |
| 1986 effective_load_flags_ |= LOAD_DISABLE_CACHE; | 1819 effective_load_flags_ |= LOAD_DISABLE_CACHE; |
| 1987 | 1820 |
| 1988 // Some headers imply load flags. The order here is significant. | 1821 // Some headers imply load flags. The order here is significant. |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2656 // blocking page is shown. An alternative would be to reverse-map the cert | 2489 // blocking page is shown. An alternative would be to reverse-map the cert |
| 2657 // status to a net error and replay the net error. | 2490 // status to a net error and replay the net error. |
| 2658 if ((response_.headers->HasHeaderValue("cache-control", "no-store")) || | 2491 if ((response_.headers->HasHeaderValue("cache-control", "no-store")) || |
| 2659 IsCertStatusError(response_.ssl_info.cert_status)) { | 2492 IsCertStatusError(response_.ssl_info.cert_status)) { |
| 2660 DoneWritingToEntry(false); | 2493 DoneWritingToEntry(false); |
| 2661 if (net_log_.IsCapturing()) | 2494 if (net_log_.IsCapturing()) |
| 2662 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); | 2495 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); |
| 2663 return OK; | 2496 return OK; |
| 2664 } | 2497 } |
| 2665 | 2498 |
| 2666 // cert_cache() will be null if the CertCacheTrial field trial is disabled. | |
| 2667 if (cache_->cert_cache() && response_.ssl_info.is_valid()) | |
| 2668 WriteCertChain(); | |
| 2669 | |
| 2670 if (truncated) | 2499 if (truncated) |
| 2671 DCHECK_EQ(200, response_.headers->response_code()); | 2500 DCHECK_EQ(200, response_.headers->response_code()); |
| 2672 | 2501 |
| 2673 // When writing headers, we normally only write the non-transient headers. | 2502 // When writing headers, we normally only write the non-transient headers. |
| 2674 bool skip_transient_headers = true; | 2503 bool skip_transient_headers = true; |
| 2675 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); | 2504 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
| 2676 response_.Persist(data->pickle(), skip_transient_headers, truncated); | 2505 response_.Persist(data->pickle(), skip_transient_headers, truncated); |
| 2677 data->Done(); | 2506 data->Done(); |
| 2678 | 2507 |
| 2679 io_buf_len_ = data->pickle()->size(); | 2508 io_buf_len_ = data->pickle()->size(); |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2945 default: | 2774 default: |
| 2946 NOTREACHED(); | 2775 NOTREACHED(); |
| 2947 } | 2776 } |
| 2948 } | 2777 } |
| 2949 | 2778 |
| 2950 void HttpCache::Transaction::OnIOComplete(int result) { | 2779 void HttpCache::Transaction::OnIOComplete(int result) { |
| 2951 DoLoop(result); | 2780 DoLoop(result); |
| 2952 } | 2781 } |
| 2953 | 2782 |
| 2954 } // namespace net | 2783 } // namespace net |
| OLD | NEW |