OLD | NEW |
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.h" |
6 | 6 |
7 #include "base/hash_tables.h" | 7 #include "base/hash_tables.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 //----------------------------------------------------------------------------- | 28 //----------------------------------------------------------------------------- |
29 // mock disk cache (a very basic memory cache implementation) | 29 // mock disk cache (a very basic memory cache implementation) |
30 | 30 |
31 class MockDiskEntry : public disk_cache::Entry, | 31 class MockDiskEntry : public disk_cache::Entry, |
32 public base::RefCounted<MockDiskEntry> { | 32 public base::RefCounted<MockDiskEntry> { |
33 public: | 33 public: |
34 MockDiskEntry() | 34 MockDiskEntry() |
35 : test_mode_(0), doomed_(false), sparse_(false), fail_requests_(false) { | 35 : test_mode_(0), doomed_(false), sparse_(false), fail_requests_(false), |
| 36 busy_(false), delayed_(false) { |
36 } | 37 } |
37 | 38 |
38 explicit MockDiskEntry(const std::string& key) | 39 explicit MockDiskEntry(const std::string& key) |
39 : key_(key), doomed_(false), sparse_(false), fail_requests_(false) { | 40 : key_(key), doomed_(false), sparse_(false), fail_requests_(false), |
| 41 busy_(false), delayed_(false) { |
40 // | 42 // |
41 // 'key' is prefixed with an identifier if it corresponds to a cached POST. | 43 // 'key' is prefixed with an identifier if it corresponds to a cached POST. |
42 // Skip past that to locate the actual URL. | 44 // Skip past that to locate the actual URL. |
43 // | 45 // |
44 // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an | 46 // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an |
45 // URL corresponding to a registered MockTransaction. It would be good to | 47 // URL corresponding to a registered MockTransaction. It would be good to |
46 // have another way to access the test_mode. | 48 // have another way to access the test_mode. |
47 // | 49 // |
48 GURL url; | 50 GURL url; |
49 if (isdigit(key[0])) { | 51 if (isdigit(key[0])) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 return net::ERR_FAILED; | 126 return net::ERR_FAILED; |
125 | 127 |
126 data_[index].resize(offset + buf_len); | 128 data_[index].resize(offset + buf_len); |
127 if (buf_len) | 129 if (buf_len) |
128 memcpy(&data_[index][offset], buf->data(), buf_len); | 130 memcpy(&data_[index][offset], buf->data(), buf_len); |
129 return buf_len; | 131 return buf_len; |
130 } | 132 } |
131 | 133 |
132 virtual int ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, | 134 virtual int ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, |
133 net::CompletionCallback* completion_callback) { | 135 net::CompletionCallback* completion_callback) { |
134 if (!sparse_) | 136 if (!sparse_ || busy_) |
135 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; | 137 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
136 if (offset < 0) | 138 if (offset < 0) |
137 return net::ERR_FAILED; | 139 return net::ERR_FAILED; |
138 | 140 |
139 if (fail_requests_) | 141 if (fail_requests_) |
140 return net::ERR_CACHE_READ_FAILURE; | 142 return net::ERR_CACHE_READ_FAILURE; |
141 | 143 |
142 DCHECK(offset < kint32max); | 144 DCHECK(offset < kint32max); |
143 int real_offset = static_cast<int>(offset); | 145 int real_offset = static_cast<int>(offset); |
144 if (!buf_len) | 146 if (!buf_len) |
145 return 0; | 147 return 0; |
146 | 148 |
147 int num = std::min(static_cast<int>(data_[1].size()) - real_offset, | 149 int num = std::min(static_cast<int>(data_[1].size()) - real_offset, |
148 buf_len); | 150 buf_len); |
149 memcpy(buf->data(), &data_[1][real_offset], num); | 151 memcpy(buf->data(), &data_[1][real_offset], num); |
150 | 152 |
151 if (!completion_callback || (test_mode_ & TEST_MODE_SYNC_CACHE_READ)) | 153 if (!completion_callback || (test_mode_ & TEST_MODE_SYNC_CACHE_READ)) |
152 return num; | 154 return num; |
153 | 155 |
154 CallbackLater(completion_callback, num); | 156 CallbackLater(completion_callback, num); |
| 157 busy_ = true; |
| 158 delayed_ = false; |
155 return net::ERR_IO_PENDING; | 159 return net::ERR_IO_PENDING; |
156 } | 160 } |
157 | 161 |
158 virtual int WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, | 162 virtual int WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, |
159 net::CompletionCallback* completion_callback) { | 163 net::CompletionCallback* completion_callback) { |
| 164 if (busy_) |
| 165 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
160 if (!sparse_) { | 166 if (!sparse_) { |
161 if (data_[1].size()) | 167 if (data_[1].size()) |
162 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; | 168 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
163 sparse_ = true; | 169 sparse_ = true; |
164 } | 170 } |
165 if (offset < 0) | 171 if (offset < 0) |
166 return net::ERR_FAILED; | 172 return net::ERR_FAILED; |
167 if (!buf_len) | 173 if (!buf_len) |
168 return 0; | 174 return 0; |
169 | 175 |
170 if (fail_requests_) | 176 if (fail_requests_) |
171 return net::ERR_CACHE_READ_FAILURE; | 177 return net::ERR_CACHE_READ_FAILURE; |
172 | 178 |
173 DCHECK(offset < kint32max); | 179 DCHECK(offset < kint32max); |
174 int real_offset = static_cast<int>(offset); | 180 int real_offset = static_cast<int>(offset); |
175 | 181 |
176 if (static_cast<int>(data_[1].size()) < real_offset + buf_len) | 182 if (static_cast<int>(data_[1].size()) < real_offset + buf_len) |
177 data_[1].resize(real_offset + buf_len); | 183 data_[1].resize(real_offset + buf_len); |
178 | 184 |
179 memcpy(&data_[1][real_offset], buf->data(), buf_len); | 185 memcpy(&data_[1][real_offset], buf->data(), buf_len); |
180 return buf_len; | 186 return buf_len; |
181 } | 187 } |
182 | 188 |
183 virtual int GetAvailableRange(int64 offset, int len, int64* start) { | 189 virtual int GetAvailableRange(int64 offset, int len, int64* start) { |
184 if (!sparse_) | 190 if (!sparse_ || busy_) |
185 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; | 191 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; |
186 if (offset < 0) | 192 if (offset < 0) |
187 return net::ERR_FAILED; | 193 return net::ERR_FAILED; |
188 | 194 |
189 if (fail_requests_) | 195 if (fail_requests_) |
190 return net::ERR_CACHE_READ_FAILURE; | 196 return net::ERR_CACHE_READ_FAILURE; |
191 | 197 |
192 *start = offset; | 198 *start = offset; |
193 DCHECK(offset < kint32max); | 199 DCHECK(offset < kint32max); |
194 int real_offset = static_cast<int>(offset); | 200 int real_offset = static_cast<int>(offset); |
(...skipping 10 matching lines...) Expand all Loading... |
205 } | 211 } |
206 } else { | 212 } else { |
207 if (!data_[1][real_offset]) | 213 if (!data_[1][real_offset]) |
208 break; | 214 break; |
209 count++; | 215 count++; |
210 } | 216 } |
211 } | 217 } |
212 return count; | 218 return count; |
213 } | 219 } |
214 | 220 |
| 221 virtual void CancelSparseIO() { cancel_ = true; } |
| 222 |
| 223 virtual int ReadyForSparseIO(net::CompletionCallback* completion_callback) { |
| 224 if (!cancel_) |
| 225 return net::OK; |
| 226 |
| 227 cancel_ = false; |
| 228 DCHECK(completion_callback); |
| 229 if (test_mode_ & TEST_MODE_SYNC_CACHE_READ) |
| 230 return net::OK; |
| 231 |
| 232 // The pending operation is already in the message loop (and hopefuly |
| 233 // already in the second pass). Just notify the caller that it finished. |
| 234 CallbackLater(completion_callback, 0); |
| 235 return net::ERR_IO_PENDING; |
| 236 } |
| 237 |
215 // Fail most subsequent requests. | 238 // Fail most subsequent requests. |
216 void set_fail_requests() { fail_requests_ = true; } | 239 void set_fail_requests() { fail_requests_ = true; } |
217 | 240 |
218 private: | 241 private: |
219 // Unlike the callbacks for MockHttpTransaction, we want this one to run even | 242 // Unlike the callbacks for MockHttpTransaction, we want this one to run even |
220 // if the consumer called Close on the MockDiskEntry. We achieve that by | 243 // if the consumer called Close on the MockDiskEntry. We achieve that by |
221 // leveraging the fact that this class is reference counted. | 244 // leveraging the fact that this class is reference counted. |
222 void CallbackLater(net::CompletionCallback* callback, int result) { | 245 void CallbackLater(net::CompletionCallback* callback, int result) { |
223 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, | 246 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, |
224 &MockDiskEntry::RunCallback, callback, result)); | 247 &MockDiskEntry::RunCallback, callback, result)); |
225 } | 248 } |
226 void RunCallback(net::CompletionCallback* callback, int result) { | 249 void RunCallback(net::CompletionCallback* callback, int result) { |
| 250 if (busy_) { |
| 251 // This is kind of hacky, but controlling the behavior of just this entry |
| 252 // from a test is sort of complicated. What we really want to do is |
| 253 // delay the delivery of a sparse IO operation a little more so that the |
| 254 // request start operation (async) will finish without seeing the end of |
| 255 // this operation (already posted to the message loop)... and without |
| 256 // just delaying for n mS (which may cause trouble with slow bots). So |
| 257 // we re-post this operation (all async sparse IO operations will take two |
| 258 // trips trhough the message loop instead of one). |
| 259 if (!delayed_) { |
| 260 delayed_ = true; |
| 261 return CallbackLater(callback, result); |
| 262 } |
| 263 } |
| 264 busy_ = false; |
227 callback->Run(result); | 265 callback->Run(result); |
228 } | 266 } |
229 | 267 |
230 std::string key_; | 268 std::string key_; |
231 std::vector<char> data_[2]; | 269 std::vector<char> data_[2]; |
232 int test_mode_; | 270 int test_mode_; |
233 bool doomed_; | 271 bool doomed_; |
234 bool sparse_; | 272 bool sparse_; |
235 bool fail_requests_; | 273 bool fail_requests_; |
| 274 bool busy_; |
| 275 bool delayed_; |
| 276 static bool cancel_; |
236 }; | 277 }; |
237 | 278 |
| 279 // Static. |
| 280 bool MockDiskEntry::cancel_ = false; |
| 281 |
238 class MockDiskCache : public disk_cache::Backend { | 282 class MockDiskCache : public disk_cache::Backend { |
239 public: | 283 public: |
240 MockDiskCache() | 284 MockDiskCache() |
241 : open_count_(0), create_count_(0), fail_requests_(false), | 285 : open_count_(0), create_count_(0), fail_requests_(false), |
242 soft_failures_(false) { | 286 soft_failures_(false) { |
243 } | 287 } |
244 | 288 |
245 ~MockDiskCache() { | 289 ~MockDiskCache() { |
246 EntryMap::iterator it = entries_.begin(); | 290 EntryMap::iterator it = entries_.begin(); |
247 for (; it != entries_.end(); ++it) | 291 for (; it != entries_.end(); ++it) |
(...skipping 2089 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2337 delete c; | 2381 delete c; |
2338 | 2382 |
2339 // Verify that the entry has not been deleted. | 2383 // Verify that the entry has not been deleted. |
2340 disk_cache::Entry* entry; | 2384 disk_cache::Entry* entry; |
2341 ASSERT_TRUE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, | 2385 ASSERT_TRUE(cache.disk_cache()->OpenEntry(kRangeGET_TransactionOK.url, |
2342 &entry)); | 2386 &entry)); |
2343 entry->Close(); | 2387 entry->Close(); |
2344 RemoveMockTransaction(&kRangeGET_TransactionOK); | 2388 RemoveMockTransaction(&kRangeGET_TransactionOK); |
2345 } | 2389 } |
2346 | 2390 |
| 2391 // Tests that we don't delete a sparse entry when we start a new request after |
| 2392 // cancelling the previous one. |
| 2393 TEST(HttpCache, RangeGET_Cancel2) { |
| 2394 MockHttpCache cache; |
| 2395 cache.http_cache()->set_enable_range_support(true); |
| 2396 AddMockTransaction(&kRangeGET_TransactionOK); |
| 2397 |
| 2398 RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); |
| 2399 MockHttpRequest request(kRangeGET_TransactionOK); |
| 2400 |
| 2401 Context* c = new Context(); |
| 2402 int rv = cache.http_cache()->CreateTransaction(&c->trans); |
| 2403 EXPECT_EQ(net::OK, rv); |
| 2404 |
| 2405 rv = c->trans->Start(&request, &c->callback, NULL); |
| 2406 if (rv == net::ERR_IO_PENDING) |
| 2407 rv = c->callback.WaitForResult(); |
| 2408 |
| 2409 EXPECT_EQ(2, cache.network_layer()->transaction_count()); |
| 2410 EXPECT_EQ(1, cache.disk_cache()->open_count()); |
| 2411 EXPECT_EQ(1, cache.disk_cache()->create_count()); |
| 2412 |
| 2413 // Make sure that we revalidate the entry and read from the cache (a single |
| 2414 // read will return while waiting for the network). |
| 2415 scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(5); |
| 2416 rv = c->trans->Read(buf, buf->size(), &c->callback); |
| 2417 EXPECT_EQ(net::ERR_IO_PENDING, rv); |
| 2418 rv = c->callback.WaitForResult(); |
| 2419 rv = c->trans->Read(buf, buf->size(), &c->callback); |
| 2420 EXPECT_EQ(net::ERR_IO_PENDING, rv); |
| 2421 |
| 2422 // Destroy the transaction before completing the read. |
| 2423 delete c; |
| 2424 |
| 2425 // We have the read and the delete (OnProcessPendingQueue) waiting on the |
| 2426 // message loop. This means that a new transaction will just reuse the same |
| 2427 // active entry (no open or create). |
| 2428 |
| 2429 RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); |
| 2430 |
| 2431 EXPECT_EQ(3, cache.network_layer()->transaction_count()); |
| 2432 EXPECT_EQ(1, cache.disk_cache()->open_count()); |
| 2433 EXPECT_EQ(1, cache.disk_cache()->create_count()); |
| 2434 RemoveMockTransaction(&kRangeGET_TransactionOK); |
| 2435 } |
| 2436 |
2347 #ifdef NDEBUG | 2437 #ifdef NDEBUG |
2348 // This test hits a NOTREACHED so it is a release mode only test. | 2438 // This test hits a NOTREACHED so it is a release mode only test. |
2349 TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) { | 2439 TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) { |
2350 MockHttpCache cache; | 2440 MockHttpCache cache; |
2351 cache.http_cache()->set_enable_range_support(true); | 2441 cache.http_cache()->set_enable_range_support(true); |
2352 AddMockTransaction(&kRangeGET_TransactionOK); | 2442 AddMockTransaction(&kRangeGET_TransactionOK); |
2353 | 2443 |
2354 // Write to the cache (40-49). | 2444 // Write to the cache (40-49). |
2355 RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); | 2445 RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK); |
2356 EXPECT_EQ(1, cache.network_layer()->transaction_count()); | 2446 EXPECT_EQ(1, cache.network_layer()->transaction_count()); |
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2917 std::string headers; | 3007 std::string headers; |
2918 response.headers->GetNormalizedHeaders(&headers); | 3008 response.headers->GetNormalizedHeaders(&headers); |
2919 | 3009 |
2920 EXPECT_EQ("HTTP/1.1 200 OK\n" | 3010 EXPECT_EQ("HTTP/1.1 200 OK\n" |
2921 "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" | 3011 "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" |
2922 "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", | 3012 "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", |
2923 headers); | 3013 headers); |
2924 | 3014 |
2925 RemoveMockTransaction(&mock_network_response); | 3015 RemoveMockTransaction(&mock_network_response); |
2926 } | 3016 } |
OLD | NEW |