| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/platform_file.h" | |
| 10 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 11 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 12 #include "net/base/load_flags.h" | 11 #include "net/base/load_flags.h" |
| 13 #include "net/disk_cache/disk_cache.h" | 12 #include "net/disk_cache/disk_cache.h" |
| 14 #include "net/http/http_request_info.h" | 13 #include "net/http/http_request_info.h" |
| 15 #include "net/http/http_response_info.h" | 14 #include "net/http/http_response_info.h" |
| 16 #include "net/http/http_transaction.h" | 15 #include "net/http/http_transaction.h" |
| 17 #include "net/http/http_transaction_unittest.h" | 16 #include "net/http/http_transaction_unittest.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 19 | 18 |
| 20 using base::Time; | 19 using base::Time; |
| 21 | 20 |
| 22 namespace { | 21 namespace { |
| 23 | 22 |
| 24 //----------------------------------------------------------------------------- | 23 //----------------------------------------------------------------------------- |
| 25 // mock disk cache (a very basic memory cache implementation) | 24 // mock disk cache (a very basic memory cache implementation) |
| 26 | 25 |
| 27 class MockDiskEntry : public disk_cache::Entry, | 26 class MockDiskEntry : public disk_cache::Entry, |
| 28 public base::RefCounted<MockDiskEntry> { | 27 public base::RefCounted<MockDiskEntry> { |
| 29 public: | 28 public: |
| 30 MockDiskEntry() | 29 MockDiskEntry() |
| 31 : test_mode_(0), doomed_(false), platform_file_(global_platform_file_) { | 30 : test_mode_(0), doomed_(false) { |
| 32 } | 31 } |
| 33 | 32 |
| 34 MockDiskEntry(const std::string& key) | 33 MockDiskEntry(const std::string& key) |
| 35 : key_(key), doomed_(false), platform_file_(global_platform_file_) { | 34 : key_(key), doomed_(false) { |
| 36 // | 35 // |
| 37 // 'key' is prefixed with an identifier if it corresponds to a cached POST. | 36 // 'key' is prefixed with an identifier if it corresponds to a cached POST. |
| 38 // Skip past that to locate the actual URL. | 37 // Skip past that to locate the actual URL. |
| 39 // | 38 // |
| 40 // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an | 39 // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an |
| 41 // URL corresponding to a registered MockTransaction. It would be good to | 40 // URL corresponding to a registered MockTransaction. It would be good to |
| 42 // have another way to access the test_mode. | 41 // have another way to access the test_mode. |
| 43 // | 42 // |
| 44 GURL url; | 43 GURL url; |
| 45 if (isdigit(key[0])) { | 44 if (isdigit(key[0])) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 | 109 |
| 111 if (offset < 0 || offset > static_cast<int>(data_[index].size())) | 110 if (offset < 0 || offset > static_cast<int>(data_[index].size())) |
| 112 return net::ERR_FAILED; | 111 return net::ERR_FAILED; |
| 113 | 112 |
| 114 data_[index].resize(offset + buf_len); | 113 data_[index].resize(offset + buf_len); |
| 115 if (buf_len) | 114 if (buf_len) |
| 116 memcpy(&data_[index][offset], buf->data(), buf_len); | 115 memcpy(&data_[index][offset], buf->data(), buf_len); |
| 117 return buf_len; | 116 return buf_len; |
| 118 } | 117 } |
| 119 | 118 |
| 120 base::PlatformFile UseExternalFile(int index) { | |
| 121 return platform_file_; | |
| 122 } | |
| 123 | |
| 124 base::PlatformFile GetPlatformFile(int index) { | |
| 125 return platform_file_; | |
| 126 } | |
| 127 | |
| 128 static void set_global_platform_file(base::PlatformFile platform_file) { | |
| 129 global_platform_file_ = platform_file; | |
| 130 } | |
| 131 | |
| 132 private: | 119 private: |
| 133 // Unlike the callbacks for MockHttpTransaction, we want this one to run even | 120 // Unlike the callbacks for MockHttpTransaction, we want this one to run even |
| 134 // if the consumer called Close on the MockDiskEntry. We achieve that by | 121 // if the consumer called Close on the MockDiskEntry. We achieve that by |
| 135 // leveraging the fact that this class is reference counted. | 122 // leveraging the fact that this class is reference counted. |
| 136 void CallbackLater(net::CompletionCallback* callback, int result) { | 123 void CallbackLater(net::CompletionCallback* callback, int result) { |
| 137 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, | 124 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 138 &MockDiskEntry::RunCallback, callback, result)); | 125 &MockDiskEntry::RunCallback, callback, result)); |
| 139 } | 126 } |
| 140 void RunCallback(net::CompletionCallback* callback, int result) { | 127 void RunCallback(net::CompletionCallback* callback, int result) { |
| 141 callback->Run(result); | 128 callback->Run(result); |
| 142 } | 129 } |
| 143 | 130 |
| 144 std::string key_; | 131 std::string key_; |
| 145 std::vector<char> data_[2]; | 132 std::vector<char> data_[2]; |
| 146 int test_mode_; | 133 int test_mode_; |
| 147 bool doomed_; | 134 bool doomed_; |
| 148 base::PlatformFile platform_file_; | |
| 149 static base::PlatformFile global_platform_file_; | |
| 150 }; | 135 }; |
| 151 | 136 |
| 152 base::PlatformFile MockDiskEntry::global_platform_file_ = | |
| 153 base::kInvalidPlatformFileValue; | |
| 154 | |
| 155 class MockDiskCache : public disk_cache::Backend { | 137 class MockDiskCache : public disk_cache::Backend { |
| 156 public: | 138 public: |
| 157 MockDiskCache() : open_count_(0), create_count_(0), fail_requests_(0) { | 139 MockDiskCache() : open_count_(0), create_count_(0), fail_requests_(0) { |
| 158 } | 140 } |
| 159 | 141 |
| 160 ~MockDiskCache() { | 142 ~MockDiskCache() { |
| 161 EntryMap::iterator it = entries_.begin(); | 143 EntryMap::iterator it = entries_.begin(); |
| 162 for (; it != entries_.end(); ++it) | 144 for (; it != entries_.end(); ++it) |
| 163 it->second->Release(); | 145 it->second->Release(); |
| 164 } | 146 } |
| (...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 } | 1232 } |
| 1251 | 1233 |
| 1252 // Ensure that we don't crash by if left-behind transactions. | 1234 // Ensure that we don't crash by if left-behind transactions. |
| 1253 TEST(HttpCache, OutlivedTransactions) { | 1235 TEST(HttpCache, OutlivedTransactions) { |
| 1254 MockHttpCache* cache = new MockHttpCache; | 1236 MockHttpCache* cache = new MockHttpCache; |
| 1255 | 1237 |
| 1256 net::HttpTransaction* trans = cache->http_cache()->CreateTransaction(); | 1238 net::HttpTransaction* trans = cache->http_cache()->CreateTransaction(); |
| 1257 delete cache; | 1239 delete cache; |
| 1258 delete trans; | 1240 delete trans; |
| 1259 } | 1241 } |
| 1260 | |
| 1261 // Make sure Entry::UseExternalFile is called when a new entry is created in | |
| 1262 // a HttpCache with MEDIA type. Also make sure Entry::GetPlatformFile is called | |
| 1263 // when an entry is loaded from a HttpCache with MEDIA type. Also confirm we | |
| 1264 // will receive a file handle in ResponseInfo from a media cache. | |
| 1265 TEST(HttpCache, SimpleGET_MediaCache) { | |
| 1266 // Initialize the HttpCache with MEDIA_CACHE type. | |
| 1267 MockHttpCache cache; | |
| 1268 cache.http_cache()->set_type(net::MEDIA_CACHE); | |
| 1269 | |
| 1270 // Define some fake file handles for testing. | |
| 1271 base::PlatformFile kFakePlatformFile1, kFakePlatformFile2; | |
| 1272 #if defined(OS_WIN) | |
| 1273 kFakePlatformFile1 = reinterpret_cast<base::PlatformFile>(1); | |
| 1274 kFakePlatformFile2 = reinterpret_cast<base::PlatformFile>(2); | |
| 1275 #else | |
| 1276 kFakePlatformFile1 = 1; | |
| 1277 kFakePlatformFile2 = 2; | |
| 1278 #endif | |
| 1279 | |
| 1280 ScopedMockTransaction trans_info(kSimpleGET_Transaction); | |
| 1281 trans_info.load_flags |= net::LOAD_ENABLE_DOWNLOAD_FILE; | |
| 1282 TestCompletionCallback callback; | |
| 1283 | |
| 1284 { | |
| 1285 // Set the fake file handle to MockDiskEntry so cache is written with an | |
| 1286 // entry created with our fake file handle. | |
| 1287 MockDiskEntry::set_global_platform_file(kFakePlatformFile1); | |
| 1288 | |
| 1289 scoped_ptr<net::HttpTransaction> trans( | |
| 1290 cache.http_cache()->CreateTransaction()); | |
| 1291 ASSERT_TRUE(trans.get()); | |
| 1292 | |
| 1293 MockHttpRequest request(trans_info); | |
| 1294 | |
| 1295 int rv = trans->Start(&request, &callback); | |
| 1296 if (rv == net::ERR_IO_PENDING) | |
| 1297 rv = callback.WaitForResult(); | |
| 1298 ASSERT_EQ(net::OK, rv); | |
| 1299 | |
| 1300 const net::HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1301 ASSERT_TRUE(response); | |
| 1302 | |
| 1303 ASSERT_EQ(kFakePlatformFile1, response->response_data_file); | |
| 1304 | |
| 1305 ReadAndVerifyTransaction(trans.get(), trans_info); | |
| 1306 } | |
| 1307 | |
| 1308 // Load only from cache so we would get the same file handle. | |
| 1309 trans_info.load_flags |= net::LOAD_ONLY_FROM_CACHE; | |
| 1310 | |
| 1311 { | |
| 1312 // Set a different file handle value to MockDiskEntry so any new entry | |
| 1313 // created in the cache won't have the same file handle value. | |
| 1314 MockDiskEntry::set_global_platform_file(kFakePlatformFile2); | |
| 1315 | |
| 1316 scoped_ptr<net::HttpTransaction> trans( | |
| 1317 cache.http_cache()->CreateTransaction()); | |
| 1318 ASSERT_TRUE(trans.get()); | |
| 1319 | |
| 1320 MockHttpRequest request(trans_info); | |
| 1321 | |
| 1322 int rv = trans->Start(&request, &callback); | |
| 1323 if (rv == net::ERR_IO_PENDING) | |
| 1324 rv = callback.WaitForResult(); | |
| 1325 ASSERT_EQ(net::OK, rv); | |
| 1326 | |
| 1327 const net::HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1328 ASSERT_TRUE(response); | |
| 1329 | |
| 1330 // Make sure we get the same file handle as in the first request. | |
| 1331 ASSERT_EQ(kFakePlatformFile1, response->response_data_file); | |
| 1332 | |
| 1333 ReadAndVerifyTransaction(trans.get(), trans_info); | |
| 1334 } | |
| 1335 } | |
| OLD | NEW |