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.h" | 5 #include "net/http/http_cache.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <memory> | 10 #include <memory> |
11 #include <utility> | 11 #include <utility> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/bind.h" | 14 #include "base/bind.h" |
15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
16 #include "base/format_macros.h" | |
16 #include "base/macros.h" | 17 #include "base/macros.h" |
17 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
18 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
19 #include "base/run_loop.h" | 20 #include "base/run_loop.h" |
20 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
21 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
22 #include "base/test/simple_test_clock.h" | 23 #include "base/test/simple_test_clock.h" |
23 #include "net/base/cache_type.h" | 24 #include "net/base/cache_type.h" |
24 #include "net/base/elements_upload_data_stream.h" | 25 #include "net/base/elements_upload_data_stream.h" |
25 #include "net/base/host_port_pair.h" | 26 #include "net/base/host_port_pair.h" |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 base::Time(), | 297 base::Time(), |
297 "", | 298 "", |
298 LOAD_VALIDATE_CACHE, | 299 LOAD_VALIDATE_CACHE, |
299 "HTTP/1.1 200 OK", | 300 "HTTP/1.1 200 OK", |
300 "Cache-Control: max-age=10000\n", | 301 "Cache-Control: max-age=10000\n", |
301 base::Time(), | 302 base::Time(), |
302 "<html><body>Google Blah Blah</body></html>", | 303 "<html><body>Google Blah Blah</body></html>", |
303 TEST_MODE_SYNC_NET_START, | 304 TEST_MODE_SYNC_NET_START, |
304 &FastTransactionServer::FastNoStoreHandler, | 305 &FastTransactionServer::FastNoStoreHandler, |
305 nullptr, | 306 nullptr, |
307 nullptr, | |
306 0, | 308 0, |
307 0, | 309 0, |
308 OK}; | 310 OK}; |
309 | 311 |
310 // This class provides a handler for kRangeGET_TransactionOK so that the range | 312 // This class provides a handler for kRangeGET_TransactionOK so that the range |
311 // request can be served on demand. | 313 // request can be served on demand. |
312 class RangeTransactionServer { | 314 class RangeTransactionServer { |
313 public: | 315 public: |
314 RangeTransactionServer() { | 316 RangeTransactionServer() { |
315 not_modified_ = false; | 317 not_modified_ = false; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
454 response_headers->replace(response_headers->find("Content-Length:"), | 456 response_headers->replace(response_headers->find("Content-Length:"), |
455 content_length.size(), content_length); | 457 content_length.size(), content_length); |
456 } | 458 } |
457 } else { | 459 } else { |
458 response_status->assign("HTTP/1.1 304 Not Modified"); | 460 response_status->assign("HTTP/1.1 304 Not Modified"); |
459 response_data->clear(); | 461 response_data->clear(); |
460 } | 462 } |
461 } | 463 } |
462 | 464 |
463 const MockTransaction kRangeGET_TransactionOK = { | 465 const MockTransaction kRangeGET_TransactionOK = { |
464 "http://www.google.com/range", | 466 "http://www.google.com/range", "GET", base::Time(), |
465 "GET", | 467 "Range: bytes = 40-49\r\n" EXTRA_HEADER, LOAD_NORMAL, |
466 base::Time(), | |
467 "Range: bytes = 40-49\r\n" EXTRA_HEADER, | |
468 LOAD_NORMAL, | |
469 "HTTP/1.1 206 Partial Content", | 468 "HTTP/1.1 206 Partial Content", |
470 "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" | 469 "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" |
471 "ETag: \"foo\"\n" | 470 "ETag: \"foo\"\n" |
472 "Accept-Ranges: bytes\n" | 471 "Accept-Ranges: bytes\n" |
473 "Content-Length: 10\n", | 472 "Content-Length: 10\n", |
474 base::Time(), | 473 base::Time(), "rg: 40-49 ", TEST_MODE_NORMAL, |
475 "rg: 40-49 ", | 474 &RangeTransactionServer::RangeHandler, nullptr, nullptr, 0, 0, OK}; |
476 TEST_MODE_NORMAL, | |
477 &RangeTransactionServer::RangeHandler, | |
478 nullptr, | |
479 0, | |
480 0, | |
481 OK}; | |
482 | 475 |
483 const char kFullRangeData[] = | 476 const char kFullRangeData[] = |
484 "rg: 00-09 rg: 10-19 rg: 20-29 rg: 30-39 " | 477 "rg: 00-09 rg: 10-19 rg: 20-29 rg: 30-39 " |
485 "rg: 40-49 rg: 50-59 rg: 60-69 rg: 70-79 "; | 478 "rg: 40-49 rg: 50-59 rg: 60-69 rg: 70-79 "; |
486 | 479 |
487 // Verifies the response headers (|response|) match a partial content | 480 // Verifies the response headers (|response|) match a partial content |
488 // response for the range starting at |start| and ending at |end|. | 481 // response for the range starting at |start| and ending at |end|. |
489 void Verify206Response(const std::string& response, int start, int end) { | 482 void Verify206Response(const std::string& response, int start, int end) { |
490 std::string raw_headers( | 483 std::string raw_headers( |
491 HttpUtil::AssembleRawHeaders(response.data(), response.size())); | 484 HttpUtil::AssembleRawHeaders(response.data(), response.size())); |
(...skipping 6557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7049 EXPECT_GT(callback.GetResult(rv), 0); | 7042 EXPECT_GT(callback.GetResult(rv), 0); |
7050 rv = trans->Read(buf.get(), 256, callback.callback()); | 7043 rv = trans->Read(buf.get(), 256, callback.callback()); |
7051 EXPECT_EQ(callback.GetResult(rv), 0); | 7044 EXPECT_EQ(callback.GetResult(rv), 0); |
7052 } | 7045 } |
7053 | 7046 |
7054 // Verify that the disk entry was updated. | 7047 // Verify that the disk entry was updated. |
7055 VerifyTruncatedFlag(&cache, kRangeGET_TransactionOK.url, false, 80); | 7048 VerifyTruncatedFlag(&cache, kRangeGET_TransactionOK.url, false, 80); |
7056 RemoveMockTransaction(&kRangeGET_TransactionOK); | 7049 RemoveMockTransaction(&kRangeGET_TransactionOK); |
7057 } | 7050 } |
7058 | 7051 |
7052 namespace { | |
7053 | |
7054 enum class TransactionPhase { | |
7055 BEFORE_FIRST_READ, | |
7056 AFTER_FIRST_READ, | |
7057 AFTER_NETWORK_READ | |
7058 }; | |
7059 | |
7060 using CacheInitializer = void (*)(MockHttpCache*); | |
7061 using HugeCacheTestConfiguration = | |
7062 std::pair<TransactionPhase, CacheInitializer>; | |
7063 | |
7064 class HttpCacheHugeResourceTest | |
7065 : public ::testing::TestWithParam<HugeCacheTestConfiguration> { | |
7066 public: | |
7067 static std::list<HugeCacheTestConfiguration> GetTestModes(); | |
7068 static std::list<HugeCacheTestConfiguration> kTestModes; | |
7069 | |
7070 // CacheInitializer callbacks. These are used to initialize the cache | |
7071 // depending on the test run configuration. | |
7072 | |
7073 // Initializes a cache containing a truncated entry containing the first 20 | |
7074 // bytes of the reponse body. | |
7075 static void SetupTruncatedCacheEntry(MockHttpCache* cache); | |
7076 | |
7077 // Initializes a cache containing a sparse entry. The first 10 bytes are | |
7078 // present in the cache. | |
7079 static void SetupPrefixSparseCacheEntry(MockHttpCache* cache); | |
7080 | |
7081 // Initializes a cache containing a sparse entry. The 10 bytes at offset | |
7082 // 99990 are present in the cache. | |
7083 static void SetupInfixSparseCacheEntry(MockHttpCache* cache); | |
7084 | |
7085 protected: | |
7086 static void LargeResourceTransactionHandler( | |
7087 const net::HttpRequestInfo* request, | |
7088 std::string* response_status, | |
7089 std::string* response_headers, | |
7090 std::string* response_data); | |
7091 static int LargeBufferReader(int64_t content_length, | |
7092 int64_t offset, | |
7093 net::IOBuffer* buf, | |
7094 int buf_len); | |
7095 | |
7096 static void SetFlagOnBeforeNetworkStart(bool* started, bool* /* defer */); | |
7097 | |
7098 // Size of resource to be tested. | |
7099 static const int64_t kTotalSize = | |
7100 5000000000LL; // Five beeeeeelllliooonn bytes! | |
gavinp
2016/06/28 14:24:43
Nit: can we write this as 5000 * 1000 * 1000 just
asanka
2016/06/28 16:55:38
Rewritten as 5'00'00'00'000LL :P
| |
7101 }; | |
7102 | |
7103 const int64_t HttpCacheHugeResourceTest::kTotalSize; | |
gavinp
2016/06/28 14:24:43
Is this necessary?
asanka
2016/06/28 16:55:38
Apparently EXPECT_EQ(kTotalSize, ...) results in a
| |
7104 | |
7105 // static | |
7106 void HttpCacheHugeResourceTest::LargeResourceTransactionHandler( | |
7107 const net::HttpRequestInfo* request, | |
7108 std::string* response_status, | |
7109 std::string* response_headers, | |
7110 std::string* response_data) { | |
7111 std::string if_range; | |
7112 if (!request->extra_headers.GetHeader(net::HttpRequestHeaders::kIfRange, | |
7113 &if_range)) { | |
7114 // If there were no range headers in the request, we are going to just | |
7115 // return the entire response body. | |
7116 response_status->assign("HTTP/1.1 200 Success"); | |
gavinp
2016/06/28 14:24:43
Nit: I know this was probably cut and paste, but y
asanka
2016/06/28 16:55:37
Done.
| |
7117 response_headers->assign(base::StringPrintf("Content-Length: %" PRId64 "\n" | |
7118 "ETag: \"foo\"\n" | |
7119 "Accept-Ranges: bytes\n", | |
7120 kTotalSize)); | |
7121 return; | |
7122 } | |
7123 | |
7124 // From this point on, we should be processing a valid byte-range request. | |
7125 EXPECT_EQ("\"foo\"", if_range); | |
7126 | |
7127 std::string range_header; | |
7128 EXPECT_TRUE(request->extra_headers.GetHeader(net::HttpRequestHeaders::kRange, | |
7129 &range_header)); | |
7130 std::vector<net::HttpByteRange> ranges; | |
7131 | |
7132 EXPECT_TRUE(net::HttpUtil::ParseRangeHeader(range_header, &ranges)); | |
7133 ASSERT_EQ(1u, ranges.size()); | |
7134 | |
7135 net::HttpByteRange range = ranges[0]; | |
7136 EXPECT_TRUE(range.HasFirstBytePosition()); | |
7137 int64_t last_byte_position = | |
7138 range.HasLastBytePosition() ? range.last_byte_position() : kTotalSize - 1; | |
7139 | |
7140 response_status->assign("HTTP/1.1 206 Partial"); | |
7141 response_headers->assign(base::StringPrintf( | |
7142 "Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRId64 | |
7143 "\n" | |
7144 "Content-Length: %" PRId64 "\n", | |
7145 range.first_byte_position(), last_byte_position, kTotalSize, | |
7146 last_byte_position - range.first_byte_position() + 1)); | |
7147 } | |
7148 | |
7149 // static | |
7150 int HttpCacheHugeResourceTest::LargeBufferReader(int64_t content_length, | |
7151 int64_t offset, | |
7152 net::IOBuffer* buf, | |
7153 int buf_len) { | |
7154 // This test involves reading multiple gigabytes of data. To make it run in a | |
7155 // reasonable amount of time, we are going to skip filling the buffer with | |
7156 // data. Instead the test relies on verifying that the count of bytes expected | |
7157 // at the end is correct. | |
7158 EXPECT_LT(0, content_length); | |
7159 EXPECT_LE(offset, content_length); | |
7160 int num = std::min(static_cast<int64_t>(buf_len), content_length - offset); | |
7161 return num; | |
7162 } | |
7163 | |
7164 // static | |
7165 void HttpCacheHugeResourceTest::SetFlagOnBeforeNetworkStart(bool* started, | |
7166 bool* /* defer */) { | |
7167 *started = true; | |
7168 } | |
7169 | |
7170 // static | |
7171 void HttpCacheHugeResourceTest::SetupTruncatedCacheEntry(MockHttpCache* cache) { | |
7172 ScopedMockTransaction scoped_transaction(kRangeGET_TransactionOK); | |
7173 std::string cached_headers = base::StringPrintf( | |
7174 "HTTP/1.1 200 OK\n" | |
7175 "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" | |
7176 "ETag: \"foo\"\n" | |
7177 "Accept-Ranges: bytes\n" | |
7178 "Content-Length: %" PRId64 "\n", | |
7179 kTotalSize); | |
7180 CreateTruncatedEntry(cached_headers, cache); | |
7181 } | |
7182 | |
7183 // static | |
7184 void HttpCacheHugeResourceTest::SetupPrefixSparseCacheEntry( | |
7185 MockHttpCache* cache) { | |
7186 MockTransaction transaction(kRangeGET_TransactionOK); | |
7187 transaction.handler = nullptr; | |
7188 transaction.request_headers = "Range: bytes = 0-9\r\n" EXTRA_HEADER; | |
7189 transaction.response_headers = | |
7190 "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" | |
7191 "ETag: \"foo\"\n" | |
7192 "Accept-Ranges: bytes\n" | |
7193 "Content-Range: bytes 0-9/5000000000\n" | |
7194 "Content-Length: 10\n"; | |
7195 AddMockTransaction(&transaction); | |
7196 std::string headers; | |
7197 RunTransactionTestWithResponse(cache->http_cache(), transaction, &headers); | |
7198 RemoveMockTransaction(&transaction); | |
7199 } | |
7200 | |
7201 // static | |
7202 void HttpCacheHugeResourceTest::SetupInfixSparseCacheEntry( | |
7203 MockHttpCache* cache) { | |
7204 MockTransaction transaction(kRangeGET_TransactionOK); | |
7205 transaction.handler = nullptr; | |
7206 transaction.request_headers = "Range: bytes = 99990-99999\r\n" EXTRA_HEADER; | |
7207 transaction.response_headers = | |
7208 "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" | |
7209 "ETag: \"foo\"\n" | |
7210 "Accept-Ranges: bytes\n" | |
7211 "Content-Range: bytes 99990-99999/5000000000\n" | |
7212 "Content-Length: 10\n"; | |
7213 AddMockTransaction(&transaction); | |
7214 std::string headers; | |
7215 RunTransactionTestWithResponse(cache->http_cache(), transaction, &headers); | |
7216 RemoveMockTransaction(&transaction); | |
7217 } | |
7218 | |
7219 // static | |
7220 std::list<HugeCacheTestConfiguration> | |
7221 HttpCacheHugeResourceTest::GetTestModes() { | |
7222 std::list<HugeCacheTestConfiguration> test_modes; | |
7223 const TransactionPhase kTransactionPhases[] = { | |
7224 TransactionPhase::BEFORE_FIRST_READ, TransactionPhase::AFTER_FIRST_READ, | |
7225 TransactionPhase::AFTER_NETWORK_READ}; | |
7226 const CacheInitializer kInitializers[] = {&SetupTruncatedCacheEntry, | |
7227 &SetupPrefixSparseCacheEntry, | |
7228 &SetupInfixSparseCacheEntry}; | |
7229 | |
7230 for (const auto phase : kTransactionPhases) | |
7231 for (const auto initializer : kInitializers) | |
7232 test_modes.push_back(std::make_pair(phase, initializer)); | |
7233 | |
7234 return test_modes; | |
7235 } | |
7236 | |
7237 // static | |
7238 std::list<HugeCacheTestConfiguration> HttpCacheHugeResourceTest::kTestModes = | |
7239 HttpCacheHugeResourceTest::GetTestModes(); | |
7240 | |
7241 INSTANTIATE_TEST_CASE_P( | |
7242 _, | |
7243 HttpCacheHugeResourceTest, | |
7244 ::testing::ValuesIn(HttpCacheHugeResourceTest::kTestModes)); | |
7245 | |
7246 } // namespace | |
7247 | |
7248 // Test what happens when StopCaching() is called while reading a huge resource | |
7249 // fetched via GET. Various combinations of cache state and when StopCaching() | |
7250 // is called is controlled by the parameter passed into the test via the | |
7251 // INSTANTIATE_TEST_CASE_P invocation above. | |
7252 TEST_P(HttpCacheHugeResourceTest, | |
7253 StopCachingFollowedByReadForHugeTruncatedResource) { | |
7254 // This test is going to be repeated for all combinations of TransactionPhase | |
7255 // and CacheInitializers returned by GetTestModes(). | |
7256 const TransactionPhase stop_caching_phase = GetParam().first; | |
7257 const CacheInitializer cache_initializer = GetParam().second; | |
7258 | |
7259 MockHttpCache cache; | |
7260 (*cache_initializer)(&cache); | |
7261 | |
7262 MockTransaction transaction(kSimpleGET_Transaction); | |
7263 transaction.url = kRangeGET_TransactionOK.url; | |
7264 transaction.handler = &LargeResourceTransactionHandler; | |
7265 transaction.read_handler = &LargeBufferReader; | |
7266 ScopedMockTransaction scoped_transaction(transaction); | |
7267 | |
7268 MockHttpRequest request(transaction); | |
7269 net::TestCompletionCallback callback; | |
7270 std::unique_ptr<net::HttpTransaction> http_transaction; | |
7271 int rv = cache.http_cache()->CreateTransaction(net::DEFAULT_PRIORITY, | |
7272 &http_transaction); | |
7273 ASSERT_EQ(net::OK, rv); | |
7274 ASSERT_TRUE(http_transaction.get()); | |
7275 | |
7276 bool network_transaction_started = false; | |
7277 if (stop_caching_phase == TransactionPhase::AFTER_NETWORK_READ) { | |
7278 http_transaction->SetBeforeNetworkStartCallback( | |
7279 base::Bind(&SetFlagOnBeforeNetworkStart, &network_transaction_started)); | |
7280 } | |
7281 | |
7282 rv = http_transaction->Start(&request, callback.callback(), | |
7283 net::BoundNetLog()); | |
7284 rv = callback.GetResult(rv); | |
7285 ASSERT_EQ(net::OK, rv); | |
7286 | |
7287 if (stop_caching_phase == TransactionPhase::BEFORE_FIRST_READ) | |
7288 http_transaction->StopCaching(); | |
7289 | |
7290 int64_t total_bytes_received = 0; | |
7291 | |
7292 EXPECT_EQ(kTotalSize, | |
7293 http_transaction->GetResponseInfo()->headers->GetContentLength()); | |
7294 do { | |
7295 // This test simulates reading Gigabytes of data. Buffer size is set to 10MB | |
gavinp
2016/06/28 14:24:43
Nit: I don't believe we need to capitalise gigabyt
asanka
2016/06/28 16:55:38
Done.
| |
7296 // to reduce the number of reads and speedup the test. | |
gavinp
2016/06/28 14:24:43
Nit: speedup is a noun, I believe you want "speed
asanka
2016/06/28 16:55:38
Done.
| |
7297 const int kBufferSize = 1024 * 1024 * 10; | |
7298 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufferSize)); | |
7299 rv = http_transaction->Read(buf.get(), kBufferSize, callback.callback()); | |
7300 rv = callback.GetResult(rv); | |
7301 | |
7302 if (stop_caching_phase == TransactionPhase::AFTER_FIRST_READ && | |
7303 total_bytes_received == 0) { | |
7304 http_transaction->StopCaching(); | |
7305 } | |
7306 | |
7307 if (rv > 0) | |
7308 total_bytes_received += rv; | |
7309 | |
7310 if (network_transaction_started && | |
7311 stop_caching_phase == TransactionPhase::AFTER_NETWORK_READ) { | |
7312 http_transaction->StopCaching(); | |
7313 network_transaction_started = false; | |
7314 } | |
7315 } while (rv > 0); | |
7316 | |
7317 // The only verification we are going to do is that the received resource has | |
7318 // the correct size. This is sufficient to verify that the state machine | |
7319 // didn't terminate abruptly due to the StopCaching() call. | |
7320 EXPECT_EQ(kTotalSize, total_bytes_received); | |
7321 } | |
7322 | |
7059 // Tests that we detect truncated resources from the net when there is | 7323 // Tests that we detect truncated resources from the net when there is |
7060 // a Content-Length header. | 7324 // a Content-Length header. |
7061 TEST(HttpCache, TruncatedByContentLength) { | 7325 TEST(HttpCache, TruncatedByContentLength) { |
7062 MockHttpCache cache; | 7326 MockHttpCache cache; |
7063 TestCompletionCallback callback; | 7327 TestCompletionCallback callback; |
7064 | 7328 |
7065 MockTransaction transaction(kSimpleGET_Transaction); | 7329 MockTransaction transaction(kSimpleGET_Transaction); |
7066 AddMockTransaction(&transaction); | 7330 AddMockTransaction(&transaction); |
7067 transaction.response_headers = "Cache-Control: max-age=10000\n" | 7331 transaction.response_headers = "Cache-Control: max-age=10000\n" |
7068 "Content-Length: 100\n"; | 7332 "Content-Length: 100\n"; |
(...skipping 666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7735 EXPECT_EQ(1, cache.disk_cache()->open_count()); | 7999 EXPECT_EQ(1, cache.disk_cache()->open_count()); |
7736 EXPECT_EQ(1, cache.disk_cache()->create_count()); | 8000 EXPECT_EQ(1, cache.disk_cache()->create_count()); |
7737 EXPECT_TRUE(response_info.was_cached); | 8001 EXPECT_TRUE(response_info.was_cached); |
7738 | 8002 |
7739 // The new SSL state is reported. | 8003 // The new SSL state is reported. |
7740 EXPECT_EQ(status2, response_info.ssl_info.connection_status); | 8004 EXPECT_EQ(status2, response_info.ssl_info.connection_status); |
7741 EXPECT_TRUE(cert2->Equals(response_info.ssl_info.cert.get())); | 8005 EXPECT_TRUE(cert2->Equals(response_info.ssl_info.cert.get())); |
7742 } | 8006 } |
7743 | 8007 |
7744 } // namespace net | 8008 } // namespace net |
OLD | NEW |