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 |