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

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

Issue 387017: Http Cache: Split HttpCache::Transaction to its own set... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2009 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.h" 5 #include "net/http/http_cache_transaction.h"
6
7 #include <algorithm>
8 #include <string>
9 6
10 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
11 8
12 #if defined(OS_POSIX) 9 #if defined(OS_POSIX)
13 #include <unistd.h> 10 #include <unistd.h>
14 #endif 11 #endif
15 12
16 #include "base/message_loop.h"
17 #include "base/pickle.h"
18 #include "base/ref_counted.h" 13 #include "base/ref_counted.h"
19 #include "base/string_util.h" 14 #include "base/string_util.h"
20 #include "base/time.h" 15 #include "base/time.h"
21 #include "net/base/io_buffer.h" 16 #include "net/base/io_buffer.h"
22 #include "net/base/load_flags.h" 17 #include "net/base/load_flags.h"
23 #include "net/base/load_log.h" 18 #include "net/base/load_log.h"
24 #include "net/base/net_errors.h" 19 #include "net/base/net_errors.h"
25 #include "net/base/ssl_cert_request_info.h" 20 #include "net/base/ssl_cert_request_info.h"
26 #include "net/disk_cache/disk_cache.h" 21 #include "net/disk_cache/disk_cache.h"
27 #include "net/http/http_network_layer.h"
28 #include "net/http/http_network_session.h"
29 #include "net/http/http_request_info.h" 22 #include "net/http/http_request_info.h"
30 #include "net/http/http_response_headers.h" 23 #include "net/http/http_response_headers.h"
31 #include "net/http/http_response_info.h"
32 #include "net/http/http_transaction.h" 24 #include "net/http/http_transaction.h"
33 #include "net/http/http_util.h" 25 #include "net/http/http_util.h"
34 #include "net/http/partial_data.h" 26 #include "net/http/partial_data.h"
35 27
36 using base::Time; 28 using base::Time;
37 29
38 namespace net { 30 namespace net {
39 31
40 // disk cache entry data indices. 32 // disk cache entry data indices.
41 enum { 33 enum {
(...skipping 20 matching lines...) Expand all
62 struct ValidationHeaderInfo { 54 struct ValidationHeaderInfo {
63 const char* request_header_name; 55 const char* request_header_name;
64 const char* related_response_header_name; 56 const char* related_response_header_name;
65 }; 57 };
66 58
67 static const ValidationHeaderInfo kValidationHeaders[] = { 59 static const ValidationHeaderInfo kValidationHeaders[] = {
68 { "if-modified-since", "last-modified" }, 60 { "if-modified-since", "last-modified" },
69 { "if-none-match", "etag" }, 61 { "if-none-match", "etag" },
70 }; 62 };
71 63
72 // Helper struct to pair a header name with its value, for
73 // headers used to validate cache entries.
74 struct ValidationHeaders {
75 ValidationHeaders() : initialized(false) {}
76
77 std::string values[ARRAYSIZE_UNSAFE(kValidationHeaders)];
78 bool initialized;
79 };
80
81 // If the request includes one of these request headers, then avoid reusing 64 // If the request includes one of these request headers, then avoid reusing
82 // our cached copy if any. 65 // our cached copy if any.
83 static const HeaderNameAndValue kForceFetchHeaders[] = { 66 static const HeaderNameAndValue kForceFetchHeaders[] = {
84 { "cache-control", "no-cache" }, 67 { "cache-control", "no-cache" },
85 { "pragma", "no-cache" }, 68 { "pragma", "no-cache" },
86 { NULL, NULL } 69 { NULL, NULL }
87 }; 70 };
88 71
89 // If the request includes one of these request headers, then force our 72 // If the request includes one of these request headers, then force our
90 // cached copy (if any) to be revalidated before reusing it. 73 // cached copy (if any) to be revalidated before reusing it.
(...skipping 15 matching lines...) Expand all
106 while (v.GetNext()) { 89 while (v.GetNext()) {
107 if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value)) 90 if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value))
108 return true; 91 return true;
109 } 92 }
110 } 93 }
111 return false; 94 return false;
112 } 95 }
113 96
114 //----------------------------------------------------------------------------- 97 //-----------------------------------------------------------------------------
115 98
116 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* e) 99 HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support)
117 : disk_entry(e), 100 : request_(NULL),
118 writer(NULL), 101 cache_(cache->AsWeakPtr()),
119 will_process_pending_queue(false), 102 entry_(NULL),
120 doomed(false) { 103 network_trans_(NULL),
104 callback_(NULL),
105 mode_(NONE),
106 reading_(false),
107 invalid_range_(false),
108 enable_range_support_(enable_range_support),
109 truncated_(false),
110 read_offset_(0),
111 effective_load_flags_(0),
112 final_upload_progress_(0),
113 ALLOW_THIS_IN_INITIALIZER_LIST(
114 network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
115 ALLOW_THIS_IN_INITIALIZER_LIST(
116 network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
117 ALLOW_THIS_IN_INITIALIZER_LIST(
118 cache_read_callback_(new CancelableCompletionCallback<Transaction>(
119 this, &Transaction::OnCacheReadCompleted))),
120 ALLOW_THIS_IN_INITIALIZER_LIST(
121 cache_write_callback_(new CancelableCompletionCallback<Transaction>(
122 this, &Transaction::OnCacheWriteCompleted))),
123 ALLOW_THIS_IN_INITIALIZER_LIST(
124 entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
125 this, &Transaction::OnCacheEntryReady))) {
126 COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
127 ARRAYSIZE_UNSAFE(kValidationHeaders),
128 Invalid_number_of_validation_headers);
121 } 129 }
122 130
123 HttpCache::ActiveEntry::~ActiveEntry() {
124 if (disk_entry)
125 disk_entry->Close();
126 }
127
128 //-----------------------------------------------------------------------------
129
130 class HttpCache::Transaction : public HttpTransaction {
131 public:
132 Transaction(HttpCache* cache, bool enable_range_support)
133 : request_(NULL),
134 cache_(cache->AsWeakPtr()),
135 entry_(NULL),
136 network_trans_(NULL),
137 callback_(NULL),
138 mode_(NONE),
139 reading_(false),
140 invalid_range_(false),
141 enable_range_support_(enable_range_support),
142 truncated_(false),
143 read_offset_(0),
144 effective_load_flags_(0),
145 final_upload_progress_(0),
146 ALLOW_THIS_IN_INITIALIZER_LIST(
147 network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
148 ALLOW_THIS_IN_INITIALIZER_LIST(
149 network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
150 ALLOW_THIS_IN_INITIALIZER_LIST(
151 cache_read_callback_(new CancelableCompletionCallback<Transaction>(
152 this, &Transaction::OnCacheReadCompleted))),
153 ALLOW_THIS_IN_INITIALIZER_LIST(
154 cache_write_callback_(new CancelableCompletionCallback<Transaction>(
155 this, &Transaction::OnCacheWriteCompleted))),
156 ALLOW_THIS_IN_INITIALIZER_LIST(
157 entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
158 this, &Transaction::OnCacheEntryReady))) {
159 }
160
161 // Clean up the transaction.
162 virtual ~Transaction();
163
164 // HttpTransaction methods:
165 virtual int Start(const HttpRequestInfo*, CompletionCallback*, LoadLog*);
166 virtual int RestartIgnoringLastError(CompletionCallback*);
167 virtual int RestartWithCertificate(X509Certificate* client_cert,
168 CompletionCallback* callback);
169 virtual int RestartWithAuth(const std::wstring& username,
170 const std::wstring& password,
171 CompletionCallback* callback);
172 virtual bool IsReadyToRestartForAuth();
173 virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback*);
174 virtual const HttpResponseInfo* GetResponseInfo() const;
175 virtual LoadState GetLoadState() const;
176 virtual uint64 GetUploadProgress(void) const;
177
178 // The transaction has the following modes, which apply to how it may access
179 // its cache entry.
180 //
181 // o If the mode of the transaction is NONE, then it is in "pass through"
182 // mode and all methods just forward to the inner network transaction.
183 //
184 // o If the mode of the transaction is only READ, then it may only read from
185 // the cache entry.
186 //
187 // o If the mode of the transaction is only WRITE, then it may only write to
188 // the cache entry.
189 //
190 // o If the mode of the transaction is READ_WRITE, then the transaction may
191 // optionally modify the cache entry (e.g., possibly corresponding to
192 // cache validation).
193 //
194 // o If the mode of the transaction is UPDATE, then the transaction may
195 // update existing cache entries, but will never create a new entry or
196 // respond using the entry read from the cache.
197 enum Mode {
198 NONE = 0,
199 READ_META = 1 << 0,
200 READ_DATA = 1 << 1,
201 READ = READ_META | READ_DATA,
202 WRITE = 1 << 2,
203 READ_WRITE = READ | WRITE,
204 UPDATE = READ_META | WRITE, // READ_WRITE & ~READ_DATA
205 };
206
207 Mode mode() const { return mode_; }
208
209 const std::string& key() const { return cache_key_; }
210
211 // Associates this transaction with a cache entry.
212 int AddToEntry();
213
214 // Called by the HttpCache when the given disk cache entry becomes accessible
215 // to the transaction. Returns network error code.
216 int EntryAvailable(ActiveEntry* entry);
217
218 // This transaction is being deleted and we are not done writing to the cache.
219 // We need to indicate that the response data was truncated. Returns true on
220 // success.
221 bool AddTruncatedFlag();
222
223 private:
224 // This is a helper function used to trigger a completion callback. It may
225 // only be called if callback_ is non-null.
226 void DoCallback(int rv);
227
228 // This will trigger the completion callback if appropriate.
229 int HandleResult(int rv);
230
231 // Sets request_ and fields derived from it.
232 void SetRequest(LoadLog* load_log, const HttpRequestInfo* request);
233
234 // Returns true if the request should be handled exclusively by the network
235 // layer (skipping the cache entirely).
236 bool ShouldPassThrough();
237
238 // Called to begin reading from the cache. Returns network error code.
239 int BeginCacheRead();
240
241 // Called to begin validating the cache entry. Returns network error code.
242 int BeginCacheValidation();
243
244 // Called to begin validating an entry that stores partial content. Returns
245 // a network error code.
246 int BeginPartialCacheValidation();
247
248 // Validates the entry headers against the requested range and continues with
249 // the validation of the rest of the entry. Returns a network error code.
250 int ValidateEntryHeadersAndContinue(bool byte_range_requested);
251
252 // Performs the cache validation for the next chunk of data stored by the
253 // cache. If this chunk is not currently stored, starts the network request
254 // to fetch it. Returns a network error code.
255 int ContinuePartialCacheValidation();
256
257 // Called to start requests which were given an "if-modified-since" or
258 // "if-none-match" validation header by the caller (NOT when the request was
259 // conditionalized internally in response to LOAD_VALIDATE_CACHE).
260 // Returns a network error code.
261 int BeginExternallyConditionalizedRequest();
262
263 // Called to begin a network transaction. Returns network error code.
264 int BeginNetworkRequest();
265
266 // Called to restart a network transaction after an error. Returns network
267 // error code.
268 int RestartNetworkRequest();
269
270 // Called to restart a network transaction with a client certificate.
271 // Returns network error code.
272 int RestartNetworkRequestWithCertificate(X509Certificate* client_cert);
273
274 // Called to restart a network transaction with authentication credentials.
275 // Returns network error code.
276 int RestartNetworkRequestWithAuth(const std::wstring& username,
277 const std::wstring& password);
278
279 // Called to determine if we need to validate the cache entry before using it.
280 bool RequiresValidation();
281
282 // Called to make the request conditional (to ask the server if the cached
283 // copy is valid). Returns true if able to make the request conditional.
284 bool ConditionalizeRequest();
285
286 // Makes sure that a 206 response is expected. Returns a network error code.
287 bool ValidatePartialResponse(const HttpResponseHeaders* headers);
288
289 // Handles a response validation error by bypassing the cache.
290 void IgnoreRangeRequest();
291
292 // Reads data from the network.
293 int ReadFromNetwork(IOBuffer* data, int data_len);
294
295 // Reads data from the cache entry.
296 int ReadFromEntry(IOBuffer* data, int data_len);
297
298 // Called to populate response_ from the cache entry.
299 int ReadResponseInfoFromEntry();
300
301 // Called to write data to the cache entry. If the write fails, then the
302 // cache entry is destroyed. Future calls to this function will just do
303 // nothing without side-effect. Returns a network error code.
304 int WriteToEntry(int index, int offset, IOBuffer* data, int data_len,
305 CompletionCallback* callback);
306
307 // Called to write response_ to the cache entry. |truncated| indicates if the
308 // entry should be marked as incomplete.
309 void WriteResponseInfoToEntry(bool truncated);
310
311 // Called to append response data to the cache entry. Returns a network error
312 // code.
313 int AppendResponseDataToEntry(IOBuffer* data, int data_len,
314 CompletionCallback* callback);
315
316 // Called to truncate response content in the entry.
317 void TruncateResponseData();
318
319 // Called when we are done writing to the cache entry.
320 void DoneWritingToEntry(bool success);
321
322 // Deletes the current partial cache entry (sparse), and optionally removes
323 // the control object (partial_).
324 void DoomPartialEntry(bool delete_object);
325
326 // Performs the needed work after receiving data from the network.
327 int DoNetworkReadCompleted(int result);
328
329 // Performs the needed work after receiving data from the network, when
330 // working with range requests.
331 int DoPartialNetworkReadCompleted(int result);
332
333 // Performs the needed work after receiving data from the cache.
334 int DoCacheReadCompleted(int result);
335
336 // Performs the needed work after receiving data from the cache, when
337 // working with range requests.
338 int DoPartialCacheReadCompleted(int result);
339
340 // Performs the needed work after writing data to the cache.
341 int DoCacheWriteCompleted(int result);
342
343 // Called to signal completion of the network transaction's Start method:
344 void OnNetworkInfoAvailable(int result);
345
346 // Called to signal completion of the network transaction's Read method:
347 void OnNetworkReadCompleted(int result);
348
349 // Called to signal completion of the cache's ReadData method:
350 void OnCacheReadCompleted(int result);
351
352 // Called to signal completion of the cache's WriteData method:
353 void OnCacheWriteCompleted(int result);
354
355 // Called to signal completion of the cache entry's ReadyForSparseIO method:
356 void OnCacheEntryReady(int result);
357
358 scoped_refptr<LoadLog> load_log_;
359 const HttpRequestInfo* request_;
360 scoped_ptr<HttpRequestInfo> custom_request_;
361 // If extra_headers specified a "if-modified-since" or "if-none-match",
362 // |external_validation_| contains the value of those headers.
363 ValidationHeaders external_validation_;
364 base::WeakPtr<HttpCache> cache_;
365 HttpCache::ActiveEntry* entry_;
366 scoped_ptr<HttpTransaction> network_trans_;
367 CompletionCallback* callback_; // Consumer's callback.
368 HttpResponseInfo response_;
369 HttpResponseInfo auth_response_;
370 std::string cache_key_;
371 Mode mode_;
372 bool reading_; // We are already reading.
373 bool invalid_range_; // We may bypass the cache for this request.
374 bool enable_range_support_;
375 bool truncated_; // We don't have all the response data.
376 scoped_refptr<IOBuffer> read_buf_;
377 int read_buf_len_;
378 int read_offset_;
379 int effective_load_flags_;
380 scoped_ptr<PartialData> partial_; // We are dealing with range requests.
381 uint64 final_upload_progress_;
382 CompletionCallbackImpl<Transaction> network_info_callback_;
383 CompletionCallbackImpl<Transaction> network_read_callback_;
384 scoped_refptr<CancelableCompletionCallback<Transaction> >
385 cache_read_callback_;
386 scoped_refptr<CancelableCompletionCallback<Transaction> >
387 cache_write_callback_;
388 scoped_refptr<CancelableCompletionCallback<Transaction> >
389 entry_ready_callback_;
390 };
391
392 HttpCache::Transaction::~Transaction() { 131 HttpCache::Transaction::~Transaction() {
393 if (cache_) { 132 if (cache_) {
394 if (entry_) { 133 if (entry_) {
395 bool cancel_request = reading_ && enable_range_support_; 134 bool cancel_request = reading_ && enable_range_support_;
396 if (cancel_request) { 135 if (cancel_request) {
397 if (partial_.get()) { 136 if (partial_.get()) {
398 entry_->disk_entry->CancelSparseIO(); 137 entry_->disk_entry->CancelSparseIO();
399 } else { 138 } else {
400 cancel_request &= (response_.headers->response_code() == 200); 139 cancel_request &= (response_.headers->response_code() == 200);
401 } 140 }
(...skipping 1220 matching lines...) Expand 10 before | Expand all | Expand 10 after
1622 1361
1623 void HttpCache::Transaction::OnCacheWriteCompleted(int result) { 1362 void HttpCache::Transaction::OnCacheWriteCompleted(int result) {
1624 DoCacheWriteCompleted(result); 1363 DoCacheWriteCompleted(result);
1625 } 1364 }
1626 1365
1627 void HttpCache::Transaction::OnCacheEntryReady(int result) { 1366 void HttpCache::Transaction::OnCacheEntryReady(int result) {
1628 DCHECK_EQ(OK, result); 1367 DCHECK_EQ(OK, result);
1629 ValidateEntryHeadersAndContinue(true); 1368 ValidateEntryHeadersAndContinue(true);
1630 } 1369 }
1631 1370
1632 //-----------------------------------------------------------------------------
1633
1634 HttpCache::HttpCache(HostResolver* host_resolver,
1635 ProxyService* proxy_service,
1636 SSLConfigService* ssl_config_service,
1637 const FilePath& cache_dir,
1638 int cache_size)
1639 : disk_cache_dir_(cache_dir),
1640 mode_(NORMAL),
1641 type_(DISK_CACHE),
1642 network_layer_(HttpNetworkLayer::CreateFactory(
1643 host_resolver, proxy_service, ssl_config_service)),
1644 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1645 enable_range_support_(true),
1646 cache_size_(cache_size) {
1647 }
1648
1649 HttpCache::HttpCache(HttpNetworkSession* session,
1650 const FilePath& cache_dir,
1651 int cache_size)
1652 : disk_cache_dir_(cache_dir),
1653 mode_(NORMAL),
1654 type_(DISK_CACHE),
1655 network_layer_(HttpNetworkLayer::CreateFactory(session)),
1656 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1657 enable_range_support_(true),
1658 cache_size_(cache_size) {
1659 }
1660
1661 HttpCache::HttpCache(HostResolver* host_resolver,
1662 ProxyService* proxy_service,
1663 SSLConfigService* ssl_config_service,
1664 int cache_size)
1665 : mode_(NORMAL),
1666 type_(MEMORY_CACHE),
1667 network_layer_(HttpNetworkLayer::CreateFactory(
1668 host_resolver, proxy_service, ssl_config_service)),
1669 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1670 enable_range_support_(true),
1671 cache_size_(cache_size) {
1672 }
1673
1674 HttpCache::HttpCache(HttpTransactionFactory* network_layer,
1675 disk_cache::Backend* disk_cache)
1676 : mode_(NORMAL),
1677 type_(DISK_CACHE),
1678 network_layer_(network_layer),
1679 disk_cache_(disk_cache),
1680 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1681 enable_range_support_(true),
1682 cache_size_(0) {
1683 }
1684
1685 HttpCache::~HttpCache() {
1686 // If we have any active entries remaining, then we need to deactivate them.
1687 // We may have some pending calls to OnProcessPendingQueue, but since those
1688 // won't run (due to our destruction), we can simply ignore the corresponding
1689 // will_process_pending_queue flag.
1690 while (!active_entries_.empty()) {
1691 ActiveEntry* entry = active_entries_.begin()->second;
1692 entry->will_process_pending_queue = false;
1693 entry->pending_queue.clear();
1694 entry->readers.clear();
1695 entry->writer = NULL;
1696 DeactivateEntry(entry);
1697 }
1698
1699 ActiveEntriesSet::iterator it = doomed_entries_.begin();
1700 for (; it != doomed_entries_.end(); ++it)
1701 delete *it;
1702 }
1703
1704 disk_cache::Backend* HttpCache::GetBackend() {
1705 if (disk_cache_.get())
1706 return disk_cache_.get();
1707
1708 DCHECK_GE(cache_size_, 0);
1709 if (type_ == MEMORY_CACHE) {
1710 // We may end up with no folder name and no cache if the initialization
1711 // of the disk cache fails. We want to be sure that what we wanted to have
1712 // was an in-memory cache.
1713 disk_cache_.reset(disk_cache::CreateInMemoryCacheBackend(cache_size_));
1714 } else if (!disk_cache_dir_.empty()) {
1715 disk_cache_.reset(disk_cache::CreateCacheBackend(disk_cache_dir_, true,
1716 cache_size_, type_));
1717 disk_cache_dir_ = FilePath(); // Reclaim memory.
1718 }
1719 return disk_cache_.get();
1720 }
1721
1722 int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
1723 // Do lazy initialization of disk cache if needed.
1724 GetBackend();
1725 trans->reset(new HttpCache::Transaction(this, enable_range_support_));
1726 return OK;
1727 }
1728
1729 HttpCache* HttpCache::GetCache() {
1730 return this;
1731 }
1732
1733 HttpNetworkSession* HttpCache::GetSession() {
1734 net::HttpNetworkLayer* network =
1735 static_cast<net::HttpNetworkLayer*>(network_layer_.get());
1736 return network->GetSession();
1737 }
1738
1739 void HttpCache::Suspend(bool suspend) {
1740 network_layer_->Suspend(suspend);
1741 }
1742
1743 // static
1744 bool HttpCache::ParseResponseInfo(const char* data, int len,
1745 HttpResponseInfo* response_info,
1746 bool* response_truncated) {
1747 Pickle pickle(data, len);
1748 return response_info->InitFromPickle(pickle, response_truncated);
1749 }
1750
1751 // static
1752 bool HttpCache::ReadResponseInfo(disk_cache::Entry* disk_entry,
1753 HttpResponseInfo* response_info,
1754 bool* response_truncated) {
1755 int size = disk_entry->GetDataSize(kResponseInfoIndex);
1756
1757 scoped_refptr<IOBuffer> buffer = new IOBuffer(size);
1758 int rv = disk_entry->ReadData(kResponseInfoIndex, 0, buffer, size, NULL);
1759 if (rv != size) {
1760 DLOG(ERROR) << "ReadData failed: " << rv;
1761 return false;
1762 }
1763
1764 return ParseResponseInfo(buffer->data(), size, response_info,
1765 response_truncated);
1766 }
1767
1768 // static
1769 bool HttpCache::WriteResponseInfo(disk_cache::Entry* disk_entry,
1770 const HttpResponseInfo* response_info,
1771 bool skip_transient_headers,
1772 bool response_truncated) {
1773 Pickle pickle;
1774 response_info->Persist(
1775 &pickle, skip_transient_headers, response_truncated);
1776
1777 scoped_refptr<WrappedIOBuffer> data = new WrappedIOBuffer(
1778 reinterpret_cast<const char*>(pickle.data()));
1779 int len = static_cast<int>(pickle.size());
1780
1781 return disk_entry->WriteData(kResponseInfoIndex, 0, data, len, NULL,
1782 true) == len;
1783 }
1784
1785 // Generate a key that can be used inside the cache.
1786 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
1787 // Strip out the reference, username, and password sections of the URL.
1788 std::string url = HttpUtil::SpecForRequest(request->url);
1789
1790 DCHECK(mode_ != DISABLE);
1791 if (mode_ == NORMAL) {
1792 // No valid URL can begin with numerals, so we should not have to worry
1793 // about collisions with normal URLs.
1794 if (request->upload_data && request->upload_data->identifier())
1795 url.insert(0, StringPrintf("%lld/", request->upload_data->identifier()));
1796 return url;
1797 }
1798
1799 // In playback and record mode, we cache everything.
1800
1801 // Lazily initialize.
1802 if (playback_cache_map_ == NULL)
1803 playback_cache_map_.reset(new PlaybackCacheMap());
1804
1805 // Each time we request an item from the cache, we tag it with a
1806 // generation number. During playback, multiple fetches for the same
1807 // item will use the same generation number and pull the proper
1808 // instance of an URL from the cache.
1809 int generation = 0;
1810 DCHECK(playback_cache_map_ != NULL);
1811 if (playback_cache_map_->find(url) != playback_cache_map_->end())
1812 generation = (*playback_cache_map_)[url];
1813 (*playback_cache_map_)[url] = generation + 1;
1814
1815 // The key into the cache is GENERATION # + METHOD + URL.
1816 std::string result = IntToString(generation);
1817 result.append(request->method);
1818 result.append(url);
1819 return result;
1820 }
1821
1822 void HttpCache::DoomEntry(const std::string& key) {
1823 // Need to abandon the ActiveEntry, but any transaction attached to the entry
1824 // should not be impacted. Dooming an entry only means that it will no
1825 // longer be returned by FindActiveEntry (and it will also be destroyed once
1826 // all consumers are finished with the entry).
1827 ActiveEntriesMap::iterator it = active_entries_.find(key);
1828 if (it == active_entries_.end()) {
1829 disk_cache_->DoomEntry(key);
1830 } else {
1831 ActiveEntry* entry = it->second;
1832 active_entries_.erase(it);
1833
1834 // We keep track of doomed entries so that we can ensure that they are
1835 // cleaned up properly when the cache is destroyed.
1836 doomed_entries_.insert(entry);
1837
1838 entry->disk_entry->Doom();
1839 entry->doomed = true;
1840
1841 DCHECK(entry->writer || !entry->readers.empty());
1842 }
1843 }
1844
1845 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) {
1846 DCHECK(entry->doomed);
1847 DCHECK(!entry->writer);
1848 DCHECK(entry->readers.empty());
1849 DCHECK(entry->pending_queue.empty());
1850
1851 ActiveEntriesSet::iterator it = doomed_entries_.find(entry);
1852 DCHECK(it != doomed_entries_.end());
1853 doomed_entries_.erase(it);
1854
1855 delete entry;
1856 }
1857
1858 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
1859 ActiveEntriesMap::const_iterator it = active_entries_.find(key);
1860 return it != active_entries_.end() ? it->second : NULL;
1861 }
1862
1863 HttpCache::ActiveEntry* HttpCache::OpenEntry(const std::string& key) {
1864 DCHECK(!FindActiveEntry(key));
1865
1866 disk_cache::Entry* disk_entry;
1867 if (!disk_cache_->OpenEntry(key, &disk_entry))
1868 return NULL;
1869
1870 return ActivateEntry(key, disk_entry);
1871 }
1872
1873 HttpCache::ActiveEntry* HttpCache::CreateEntry(const std::string& key) {
1874 DCHECK(!FindActiveEntry(key));
1875
1876 disk_cache::Entry* disk_entry;
1877 if (!disk_cache_->CreateEntry(key, &disk_entry))
1878 return NULL;
1879
1880 return ActivateEntry(key, disk_entry);
1881 }
1882
1883 void HttpCache::DestroyEntry(ActiveEntry* entry) {
1884 if (entry->doomed) {
1885 FinalizeDoomedEntry(entry);
1886 } else {
1887 DeactivateEntry(entry);
1888 }
1889 }
1890
1891 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
1892 const std::string& key,
1893 disk_cache::Entry* disk_entry) {
1894 ActiveEntry* entry = new ActiveEntry(disk_entry);
1895 active_entries_[key] = entry;
1896 return entry;
1897 }
1898
1899 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
1900 DCHECK(!entry->will_process_pending_queue);
1901 DCHECK(!entry->doomed);
1902 DCHECK(!entry->writer);
1903 DCHECK(entry->readers.empty());
1904 DCHECK(entry->pending_queue.empty());
1905
1906 std::string key = entry->disk_entry->GetKey();
1907 if (key.empty())
1908 return SlowDeactivateEntry(entry);
1909
1910 ActiveEntriesMap::iterator it = active_entries_.find(key);
1911 DCHECK(it != active_entries_.end());
1912 DCHECK(it->second == entry);
1913
1914 active_entries_.erase(it);
1915 delete entry;
1916 }
1917
1918 // We don't know this entry's key so we have to find it without it.
1919 void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) {
1920 for (ActiveEntriesMap::iterator it = active_entries_.begin();
1921 it != active_entries_.end(); ++it) {
1922 if (it->second == entry) {
1923 active_entries_.erase(it);
1924 delete entry;
1925 break;
1926 }
1927 }
1928 }
1929
1930 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
1931 DCHECK(entry);
1932
1933 // We implement a basic reader/writer lock for the disk cache entry. If
1934 // there is already a writer, then everyone has to wait for the writer to
1935 // finish before they can access the cache entry. There can be multiple
1936 // readers.
1937 //
1938 // NOTE: If the transaction can only write, then the entry should not be in
1939 // use (since any existing entry should have already been doomed).
1940
1941 if (entry->writer || entry->will_process_pending_queue) {
1942 entry->pending_queue.push_back(trans);
1943 return ERR_IO_PENDING;
1944 }
1945
1946 if (trans->mode() & Transaction::WRITE) {
1947 // transaction needs exclusive access to the entry
1948 if (entry->readers.empty()) {
1949 entry->writer = trans;
1950 } else {
1951 entry->pending_queue.push_back(trans);
1952 return ERR_IO_PENDING;
1953 }
1954 } else {
1955 // transaction needs read access to the entry
1956 entry->readers.push_back(trans);
1957 }
1958
1959 // We do this before calling EntryAvailable to force any further calls to
1960 // AddTransactionToEntry to add their transaction to the pending queue, which
1961 // ensures FIFO ordering.
1962 if (!entry->writer && !entry->pending_queue.empty())
1963 ProcessPendingQueue(entry);
1964
1965 return trans->EntryAvailable(entry);
1966 }
1967
1968 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
1969 bool cancel) {
1970 // If we already posted a task to move on to the next transaction and this was
1971 // the writer, there is nothing to cancel.
1972 if (entry->will_process_pending_queue && entry->readers.empty())
1973 return;
1974
1975 if (entry->writer) {
1976 DCHECK(trans == entry->writer);
1977
1978 // Assume there was a failure.
1979 bool success = false;
1980 if (cancel) {
1981 DCHECK(entry->disk_entry);
1982 // This is a successful operation in the sense that we want to keep the
1983 // entry.
1984 success = trans->AddTruncatedFlag();
1985 }
1986 DoneWritingToEntry(entry, success);
1987 } else {
1988 DoneReadingFromEntry(entry, trans);
1989 }
1990 }
1991
1992 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
1993 DCHECK(entry->readers.empty());
1994
1995 entry->writer = NULL;
1996
1997 if (success) {
1998 ProcessPendingQueue(entry);
1999 } else {
2000 DCHECK(!entry->will_process_pending_queue);
2001
2002 // We failed to create this entry.
2003 TransactionList pending_queue;
2004 pending_queue.swap(entry->pending_queue);
2005
2006 entry->disk_entry->Doom();
2007 DestroyEntry(entry);
2008
2009 // We need to do something about these pending entries, which now need to
2010 // be added to a new entry.
2011 while (!pending_queue.empty()) {
2012 pending_queue.front()->AddToEntry();
2013 pending_queue.pop_front();
2014 }
2015 }
2016 }
2017
2018 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
2019 DCHECK(!entry->writer);
2020
2021 TransactionList::iterator it =
2022 std::find(entry->readers.begin(), entry->readers.end(), trans);
2023 DCHECK(it != entry->readers.end());
2024
2025 entry->readers.erase(it);
2026
2027 ProcessPendingQueue(entry);
2028 }
2029
2030 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
2031 DCHECK(entry->writer);
2032 DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
2033 DCHECK(entry->readers.empty());
2034
2035 Transaction* trans = entry->writer;
2036
2037 entry->writer = NULL;
2038 entry->readers.push_back(trans);
2039
2040 ProcessPendingQueue(entry);
2041 }
2042
2043 void HttpCache::RemovePendingTransaction(Transaction* trans) {
2044 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
2045 bool found = false;
2046 if (i != active_entries_.end())
2047 found = RemovePendingTransactionFromEntry(i->second, trans);
2048
2049 if (found)
2050 return;
2051
2052 ActiveEntriesSet::iterator it = doomed_entries_.begin();
2053 for (; it != doomed_entries_.end() && !found; ++it)
2054 found = RemovePendingTransactionFromEntry(*it, trans);
2055 }
2056
2057 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
2058 Transaction* trans) {
2059 TransactionList& pending_queue = entry->pending_queue;
2060
2061 TransactionList::iterator j =
2062 find(pending_queue.begin(), pending_queue.end(), trans);
2063 if (j == pending_queue.end())
2064 return false;
2065
2066 pending_queue.erase(j);
2067 return true;
2068 }
2069
2070 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
2071 // Multiple readers may finish with an entry at once, so we want to batch up
2072 // calls to OnProcessPendingQueue. This flag also tells us that we should
2073 // not delete the entry before OnProcessPendingQueue runs.
2074 if (entry->will_process_pending_queue)
2075 return;
2076 entry->will_process_pending_queue = true;
2077
2078 MessageLoop::current()->PostTask(FROM_HERE,
2079 task_factory_.NewRunnableMethod(&HttpCache::OnProcessPendingQueue,
2080 entry));
2081 }
2082
2083 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
2084 entry->will_process_pending_queue = false;
2085 DCHECK(!entry->writer);
2086
2087 // If no one is interested in this entry, then we can de-activate it.
2088 if (entry->pending_queue.empty()) {
2089 if (entry->readers.empty())
2090 DestroyEntry(entry);
2091 return;
2092 }
2093
2094 // Promote next transaction from the pending queue.
2095 Transaction* next = entry->pending_queue.front();
2096 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
2097 return; // Have to wait.
2098
2099 entry->pending_queue.erase(entry->pending_queue.begin());
2100
2101 AddTransactionToEntry(entry, next);
2102 }
2103
2104 void HttpCache::CloseIdleConnections() {
2105 net::HttpNetworkLayer* network =
2106 static_cast<net::HttpNetworkLayer*>(network_layer_.get());
2107 HttpNetworkSession* session = network->GetSession();
2108 if (session) {
2109 session->tcp_socket_pool()->CloseIdleSockets();
2110 }
2111 }
2112
2113 //-----------------------------------------------------------------------------
2114
2115 } // namespace net 1371 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698