blob: 1c74ca896b4efdabcc06e7d3b67c91d23629f2b7 [file] [log] [blame]
[email protected]8bf26f49a2009-06-12 17:35:501// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_cache.h"
6
[email protected]23144032008-09-08 20:51:307#include "base/hash_tables.h"
initial.commit586acc5fe2008-07-26 22:42:528#include "base/message_loop.h"
9#include "base/string_util.h"
10#include "net/base/net_errors.h"
11#include "net/base/load_flags.h"
12#include "net/disk_cache/disk_cache.h"
[email protected]8bf26f49a2009-06-12 17:35:5013#include "net/http/http_byte_range.h"
initial.commit586acc5fe2008-07-26 22:42:5214#include "net/http/http_request_info.h"
[email protected]95792eb12009-06-22 21:30:4015#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5216#include "net/http/http_response_info.h"
17#include "net/http/http_transaction.h"
18#include "net/http/http_transaction_unittest.h"
[email protected]8bf26f49a2009-06-12 17:35:5019#include "net/http/http_util.h"
initial.commit586acc5fe2008-07-26 22:42:5220#include "testing/gtest/include/gtest/gtest.h"
21
[email protected]e1acf6f2008-10-27 20:43:3322using base::Time;
23
initial.commit586acc5fe2008-07-26 22:42:5224namespace {
25
26//-----------------------------------------------------------------------------
27// mock disk cache (a very basic memory cache implementation)
28
29class MockDiskEntry : public disk_cache::Entry,
30 public base::RefCounted<MockDiskEntry> {
31 public:
[email protected]e7f29642009-03-02 22:53:1832 MockDiskEntry()
[email protected]a2068a612009-06-04 21:43:4933 : test_mode_(0), doomed_(false), sparse_(false) {
initial.commit586acc5fe2008-07-26 22:42:5234 }
35
[email protected]e7f29642009-03-02 22:53:1836 MockDiskEntry(const std::string& key)
[email protected]a2068a612009-06-04 21:43:4937 : key_(key), doomed_(false), sparse_(false) {
[email protected]96bac982009-03-24 18:20:0638 //
39 // 'key' is prefixed with an identifier if it corresponds to a cached POST.
40 // Skip past that to locate the actual URL.
41 //
42 // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an
43 // URL corresponding to a registered MockTransaction. It would be good to
44 // have another way to access the test_mode.
45 //
46 GURL url;
47 if (isdigit(key[0])) {
48 size_t slash = key.find('/');
49 DCHECK(slash != std::string::npos);
50 url = GURL(key.substr(slash + 1));
51 } else {
52 url = GURL(key);
53 }
54 const MockTransaction* t = FindMockTransaction(url);
initial.commit586acc5fe2008-07-26 22:42:5255 DCHECK(t);
56 test_mode_ = t->test_mode;
57 }
58
59 ~MockDiskEntry() {
60 }
61
62 bool is_doomed() const { return doomed_; }
63
64 virtual void Doom() {
65 doomed_ = true;
66 }
67
68 virtual void Close() {
69 Release();
70 }
71
72 virtual std::string GetKey() const {
73 return key_;
74 }
75
76 virtual Time GetLastUsed() const {
77 return Time::FromInternalValue(0);
78 }
79
80 virtual Time GetLastModified() const {
81 return Time::FromInternalValue(0);
82 }
83
84 virtual int32 GetDataSize(int index) const {
85 DCHECK(index >= 0 && index < 2);
86 return static_cast<int32>(data_[index].size());
87 }
88
[email protected]74a85ce2009-02-12 00:03:1989 virtual int ReadData(int index, int offset, net::IOBuffer* buf, int buf_len,
initial.commit586acc5fe2008-07-26 22:42:5290 net::CompletionCallback* callback) {
91 DCHECK(index >= 0 && index < 2);
92
93 if (offset < 0 || offset > static_cast<int>(data_[index].size()))
94 return net::ERR_FAILED;
[email protected]cad155b2008-09-23 14:44:2795 if (static_cast<size_t>(offset) == data_[index].size())
initial.commit586acc5fe2008-07-26 22:42:5296 return 0;
97
98 int num = std::min(buf_len, static_cast<int>(data_[index].size()) - offset);
[email protected]74a85ce2009-02-12 00:03:1999 memcpy(buf->data(), &data_[index][offset], num);
initial.commit586acc5fe2008-07-26 22:42:52100
101 if (!callback || (test_mode_ & TEST_MODE_SYNC_CACHE_READ))
102 return num;
103
104 CallbackLater(callback, num);
105 return net::ERR_IO_PENDING;
106 }
107
[email protected]74a85ce2009-02-12 00:03:19108 virtual int WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
initial.commit586acc5fe2008-07-26 22:42:52109 net::CompletionCallback* callback, bool truncate) {
110 DCHECK(index >= 0 && index < 2);
111 DCHECK(truncate);
112
113 if (offset < 0 || offset > static_cast<int>(data_[index].size()))
114 return net::ERR_FAILED;
115
116 data_[index].resize(offset + buf_len);
117 if (buf_len)
[email protected]74a85ce2009-02-12 00:03:19118 memcpy(&data_[index][offset], buf->data(), buf_len);
initial.commit586acc5fe2008-07-26 22:42:52119 return buf_len;
120 }
121
[email protected]a2068a612009-06-04 21:43:49122 virtual int ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
123 net::CompletionCallback* completion_callback) {
124 if (!sparse_)
125 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
126 if (offset < 0)
127 return net::ERR_FAILED;
128
129 DCHECK(offset < kint32max);
130 int real_offset = static_cast<int>(offset);
131 if (!buf_len)
132 return 0;
133
134 int num = std::min(static_cast<int>(data_[1].size()) - real_offset,
135 buf_len);
136 memcpy(buf->data(), &data_[1][real_offset], num);
137
138 if (!completion_callback || (test_mode_ & TEST_MODE_SYNC_CACHE_READ))
139 return num;
140
141 CallbackLater(completion_callback, num);
142 return net::ERR_IO_PENDING;
143 }
144
145 virtual int WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
146 net::CompletionCallback* completion_callback) {
147 if (!sparse_) {
148 if (data_[1].size())
149 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
150 sparse_ = true;
151 }
152 if (offset < 0)
153 return net::ERR_FAILED;
154 if (!buf_len)
155 return 0;
156
157 DCHECK(offset < kint32max);
158 int real_offset = static_cast<int>(offset);
159
160 if (static_cast<int>(data_[1].size()) < real_offset + buf_len)
161 data_[1].resize(real_offset + buf_len);
162
163 memcpy(&data_[1][real_offset], buf->data(), buf_len);
164 return buf_len;
165 }
166
167 virtual int GetAvailableRange(int64 offset, int len, int64* start) {
168 if (!sparse_)
169 return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
170 if (offset < 0)
171 return net::ERR_FAILED;
172
173 *start = offset;
174 DCHECK(offset < kint32max);
175 int real_offset = static_cast<int>(offset);
176 if (static_cast<int>(data_[1].size()) < real_offset)
177 return 0;
178
179 int num = std::min(static_cast<int>(data_[1].size()) - real_offset, len);
180 int count = 0;
181 for (; num > 0; num--, real_offset++) {
182 if (!count) {
183 if (data_[1][real_offset]) {
184 count++;
185 *start = real_offset;
186 }
187 } else {
188 if (!data_[1][real_offset])
189 break;
190 count++;
191 }
192 }
193 return count;
194 }
195
initial.commit586acc5fe2008-07-26 22:42:52196 private:
197 // Unlike the callbacks for MockHttpTransaction, we want this one to run even
198 // if the consumer called Close on the MockDiskEntry. We achieve that by
199 // leveraging the fact that this class is reference counted.
200 void CallbackLater(net::CompletionCallback* callback, int result) {
201 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
202 &MockDiskEntry::RunCallback, callback, result));
203 }
204 void RunCallback(net::CompletionCallback* callback, int result) {
205 callback->Run(result);
206 }
207
208 std::string key_;
209 std::vector<char> data_[2];
210 int test_mode_;
211 bool doomed_;
[email protected]a2068a612009-06-04 21:43:49212 bool sparse_;
initial.commit586acc5fe2008-07-26 22:42:52213};
214
215class MockDiskCache : public disk_cache::Backend {
216 public:
217 MockDiskCache() : open_count_(0), create_count_(0), fail_requests_(0) {
218 }
219
220 ~MockDiskCache() {
221 EntryMap::iterator it = entries_.begin();
222 for (; it != entries_.end(); ++it)
223 it->second->Release();
224 }
225
226 virtual int32 GetEntryCount() const {
227 return static_cast<int32>(entries_.size());
228 }
229
230 virtual bool OpenEntry(const std::string& key, disk_cache::Entry** entry) {
231 if (fail_requests_)
232 return false;
233
234 EntryMap::iterator it = entries_.find(key);
235 if (it == entries_.end())
236 return false;
237
238 if (it->second->is_doomed()) {
239 it->second->Release();
240 entries_.erase(it);
241 return false;
242 }
243
244 open_count_++;
245
246 it->second->AddRef();
247 *entry = it->second;
248
249 return true;
250 }
251
252 virtual bool CreateEntry(const std::string& key, disk_cache::Entry** entry) {
253 if (fail_requests_)
254 return false;
255
256 EntryMap::iterator it = entries_.find(key);
257 DCHECK(it == entries_.end());
258
259 create_count_++;
260
261 MockDiskEntry* new_entry = new MockDiskEntry(key);
262
263 new_entry->AddRef();
264 entries_[key] = new_entry;
265
266 new_entry->AddRef();
267 *entry = new_entry;
268
269 return true;
270 }
271
272 virtual bool DoomEntry(const std::string& key) {
273 EntryMap::iterator it = entries_.find(key);
274 if (it != entries_.end()) {
275 it->second->Release();
276 entries_.erase(it);
277 }
278 return true;
279 }
280
281 virtual bool DoomAllEntries() {
282 return false;
283 }
284
285 virtual bool DoomEntriesBetween(const Time initial_time,
286 const Time end_time) {
287 return true;
288 }
289
290 virtual bool DoomEntriesSince(const Time initial_time) {
291 return true;
292 }
293
294 virtual bool OpenNextEntry(void** iter, disk_cache::Entry** next_entry) {
295 return false;
296 }
297
298 virtual void EndEnumeration(void** iter) {}
299
300 virtual void GetStats(
301 std::vector<std::pair<std::string, std::string> >* stats) {
302 }
303
304 // returns number of times a cache entry was successfully opened
305 int open_count() const { return open_count_; }
306
307 // returns number of times a cache entry was successfully created
308 int create_count() const { return create_count_; }
309
310 // Fail any subsequent CreateEntry and OpenEntry.
311 void set_fail_requests() { fail_requests_ = true; }
312
313 private:
[email protected]23144032008-09-08 20:51:30314 typedef base::hash_map<std::string, MockDiskEntry*> EntryMap;
initial.commit586acc5fe2008-07-26 22:42:52315 EntryMap entries_;
316 int open_count_;
317 int create_count_;
318 bool fail_requests_;
319};
320
321class MockHttpCache {
322 public:
323 MockHttpCache() : http_cache_(new MockNetworkLayer(), new MockDiskCache()) {
324 }
325
326 net::HttpCache* http_cache() { return &http_cache_; }
327
328 MockNetworkLayer* network_layer() {
329 return static_cast<MockNetworkLayer*>(http_cache_.network_layer());
330 }
331 MockDiskCache* disk_cache() {
332 return static_cast<MockDiskCache*>(http_cache_.disk_cache());
333 }
334
335 private:
336 net::HttpCache http_cache_;
337};
338
339
340//-----------------------------------------------------------------------------
341// helpers
342
343void ReadAndVerifyTransaction(net::HttpTransaction* trans,
344 const MockTransaction& trans_info) {
345 std::string content;
346 int rv = ReadTransaction(trans, &content);
347
348 EXPECT_EQ(net::OK, rv);
349 EXPECT_EQ(strlen(trans_info.data), content.size());
350 EXPECT_EQ(0, memcmp(trans_info.data, content.data(), content.size()));
351}
352
[email protected]96bac982009-03-24 18:20:06353void RunTransactionTestWithRequest(net::HttpCache* cache,
354 const MockTransaction& trans_info,
[email protected]95792eb12009-06-22 21:30:40355 const MockHttpRequest& request,
356 std::string* response_headers) {
initial.commit586acc5fe2008-07-26 22:42:52357 TestCompletionCallback callback;
358
359 // write to the cache
360
[email protected]af4876d2008-10-21 23:10:57361 scoped_ptr<net::HttpTransaction> trans(cache->CreateTransaction());
362 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:52363
364 int rv = trans->Start(&request, &callback);
365 if (rv == net::ERR_IO_PENDING)
366 rv = callback.WaitForResult();
367 ASSERT_EQ(net::OK, rv);
368
369 const net::HttpResponseInfo* response = trans->GetResponseInfo();
370 ASSERT_TRUE(response);
371
[email protected]95792eb12009-06-22 21:30:40372 if (response_headers)
373 response->headers->GetNormalizedHeaders(response_headers);
374
[email protected]af4876d2008-10-21 23:10:57375 ReadAndVerifyTransaction(trans.get(), trans_info);
initial.commit586acc5fe2008-07-26 22:42:52376}
377
[email protected]96bac982009-03-24 18:20:06378void RunTransactionTest(net::HttpCache* cache,
379 const MockTransaction& trans_info) {
380 return RunTransactionTestWithRequest(
[email protected]95792eb12009-06-22 21:30:40381 cache, trans_info, MockHttpRequest(trans_info), NULL);
382}
383
384void RunTransactionTestWithResponse(net::HttpCache* cache,
385 const MockTransaction& trans_info,
386 std::string* response_headers) {
387 return RunTransactionTestWithRequest(
388 cache, trans_info, MockHttpRequest(trans_info), response_headers);
[email protected]96bac982009-03-24 18:20:06389}
390
[email protected]b367d9a52009-02-27 01:02:51391// This class provides a handler for kFastNoStoreGET_Transaction so that the
392// no-store header can be included on demand.
393class FastTransactionServer {
394 public:
395 FastTransactionServer() {
396 no_store = false;
397 }
398 ~FastTransactionServer() {}
399
400 void set_no_store(bool value) { no_store = value; }
401
402 static void FastNoStoreHandler(const net::HttpRequestInfo* request,
403 std::string* response_status,
404 std::string* response_headers,
405 std::string* response_data) {
406 if (no_store)
407 *response_headers = "Cache-Control: no-store\n";
408 }
409
410 private:
411 static bool no_store;
412 DISALLOW_COPY_AND_ASSIGN(FastTransactionServer);
413};
414bool FastTransactionServer::no_store;
415
416const MockTransaction kFastNoStoreGET_Transaction = {
417 "http://www.google.com/nostore",
418 "GET",
419 "",
420 net::LOAD_VALIDATE_CACHE,
421 "HTTP/1.1 200 OK",
422 "Cache-Control: max-age=10000\n",
423 "<html><body>Google Blah Blah</body></html>",
424 TEST_MODE_SYNC_NET_START,
425 &FastTransactionServer::FastNoStoreHandler,
426 0
427};
428
[email protected]8bf26f49a2009-06-12 17:35:50429// This class provides a handler for kRangeGET_TransactionOK so that the range
430// request can be served on demand.
431class RangeTransactionServer {
432 public:
433 RangeTransactionServer() {
434 no_store = false;
435 }
436 ~RangeTransactionServer() {}
437
438 void set_no_store(bool value) { no_store = value; }
439
440 static void RangeHandler(const net::HttpRequestInfo* request,
441 std::string* response_status,
442 std::string* response_headers,
443 std::string* response_data);
444
445 private:
446 static bool no_store;
447 DISALLOW_COPY_AND_ASSIGN(RangeTransactionServer);
448};
449
450// Static.
451void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request,
452 std::string* response_status,
453 std::string* response_headers,
454 std::string* response_data) {
455 if (request->extra_headers.empty())
456 return;
457
458 std::vector<net::HttpByteRange> ranges;
459 if (!net::HttpUtil::ParseRanges(request->extra_headers, &ranges) ||
460 ranges.size() != 1)
461 return;
462 // We can handle this range request.
463 net::HttpByteRange byte_range = ranges[0];
464 EXPECT_TRUE(byte_range.ComputeBounds(80));
465 int start = static_cast<int>(byte_range.first_byte_position());
466 int end = static_cast<int>(byte_range.last_byte_position());
467
468 EXPECT_LT(end, 80);
469
470 std::string content_range = StringPrintf("Content-Range: bytes %d-%d/80\n",
471 start, end);
472 response_headers->append(content_range);
473
474 if (request->extra_headers.find("If-None-Match") == std::string::npos) {
475 EXPECT_EQ(9, end - start);
[email protected]67fe45c2009-06-24 17:44:57476 std::string data = StringPrintf("rg: %02d-%02d ", start, end);
[email protected]8bf26f49a2009-06-12 17:35:50477 *response_data = data;
478 } else {
479 response_status->assign("HTTP/1.1 304 Not Modified");
480 response_data->clear();
481 }
482}
483
484const MockTransaction kRangeGET_TransactionOK = {
485 "http://www.google.com/range",
486 "GET",
487 "Range: bytes = 40-49\r\n",
488 net::LOAD_NORMAL,
489 "HTTP/1.1 206 Partial Content",
490 "Last-Modified: Sat, 18 Apr 2009 01:10:43 GMT\n"
491 "ETag: \"foo\"\n"
492 "Accept-Ranges: bytes\n"
493 "Content-Length: 10\n",
494 "rg: 40-49 ",
495 TEST_MODE_NORMAL,
496 &RangeTransactionServer::RangeHandler,
497 0
498};
499
[email protected]95792eb12009-06-22 21:30:40500// Returns true if the response headers (|response|) match a partial content
501// response for the range starting at |start| and ending at |end|.
502bool Verify206Response(std::string response, int start, int end) {
503 std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(),
504 response.size()));
505 scoped_refptr<net::HttpResponseHeaders> headers =
506 new net::HttpResponseHeaders(raw_headers);
507
508 if (206 != headers->response_code())
509 return false;
510
511 int64 range_start, range_end, object_size;
512 if (!headers->GetContentRange(&range_start, &range_end, &object_size))
513 return false;
514 int64 content_length = headers->GetContentLength();
515
516 int length = end - start + 1;
517 if (content_length != length)
518 return false;
519
520 if (range_start != start)
521 return false;
522
523 if (range_end != end)
524 return false;
525
526 return true;
527}
528
initial.commit586acc5fe2008-07-26 22:42:52529} // namespace
530
531
532//-----------------------------------------------------------------------------
533// tests
534
535
536TEST(HttpCache, CreateThenDestroy) {
537 MockHttpCache cache;
538
[email protected]af4876d2008-10-21 23:10:57539 scoped_ptr<net::HttpTransaction> trans(
540 cache.http_cache()->CreateTransaction());
541 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:52542}
543
544TEST(HttpCache, SimpleGET) {
545 MockHttpCache cache;
546
547 // write to the cache
548 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
549
550 EXPECT_EQ(1, cache.network_layer()->transaction_count());
551 EXPECT_EQ(0, cache.disk_cache()->open_count());
552 EXPECT_EQ(1, cache.disk_cache()->create_count());
553}
554
555TEST(HttpCache, SimpleGETNoDiskCache) {
556 MockHttpCache cache;
557
558 cache.disk_cache()->set_fail_requests();
559
560 // Read from the network, and don't use the cache.
561 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
562
563 EXPECT_EQ(1, cache.network_layer()->transaction_count());
564 EXPECT_EQ(0, cache.disk_cache()->open_count());
565 EXPECT_EQ(0, cache.disk_cache()->create_count());
566}
567
568TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) {
569 MockHttpCache cache;
570
571 // write to the cache
572 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
573
574 // force this transaction to read from the cache
575 MockTransaction transaction(kSimpleGET_Transaction);
576 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
577
578 RunTransactionTest(cache.http_cache(), transaction);
579
580 EXPECT_EQ(1, cache.network_layer()->transaction_count());
581 EXPECT_EQ(1, cache.disk_cache()->open_count());
582 EXPECT_EQ(1, cache.disk_cache()->create_count());
583}
584
585TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Miss) {
586 MockHttpCache cache;
587
588 // force this transaction to read from the cache
589 MockTransaction transaction(kSimpleGET_Transaction);
590 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
591
592 MockHttpRequest request(transaction);
593 TestCompletionCallback callback;
594
[email protected]af4876d2008-10-21 23:10:57595 scoped_ptr<net::HttpTransaction> trans(
596 cache.http_cache()->CreateTransaction());
597 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:52598
599 int rv = trans->Start(&request, &callback);
600 if (rv == net::ERR_IO_PENDING)
601 rv = callback.WaitForResult();
602 ASSERT_EQ(net::ERR_CACHE_MISS, rv);
603
[email protected]af4876d2008-10-21 23:10:57604 trans.reset();
initial.commit586acc5fe2008-07-26 22:42:52605
606 EXPECT_EQ(0, cache.network_layer()->transaction_count());
607 EXPECT_EQ(0, cache.disk_cache()->open_count());
608 EXPECT_EQ(0, cache.disk_cache()->create_count());
609}
610
611TEST(HttpCache, SimpleGET_LoadPreferringCache_Hit) {
612 MockHttpCache cache;
613
614 // write to the cache
615 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
616
617 // force this transaction to read from the cache if valid
618 MockTransaction transaction(kSimpleGET_Transaction);
619 transaction.load_flags |= net::LOAD_PREFERRING_CACHE;
620
621 RunTransactionTest(cache.http_cache(), transaction);
622
623 EXPECT_EQ(1, cache.network_layer()->transaction_count());
624 EXPECT_EQ(1, cache.disk_cache()->open_count());
625 EXPECT_EQ(1, cache.disk_cache()->create_count());
626}
627
628TEST(HttpCache, SimpleGET_LoadPreferringCache_Miss) {
629 MockHttpCache cache;
630
631 // force this transaction to read from the cache if valid
632 MockTransaction transaction(kSimpleGET_Transaction);
633 transaction.load_flags |= net::LOAD_PREFERRING_CACHE;
634
635 RunTransactionTest(cache.http_cache(), transaction);
636
637 EXPECT_EQ(1, cache.network_layer()->transaction_count());
638 EXPECT_EQ(0, cache.disk_cache()->open_count());
639 EXPECT_EQ(1, cache.disk_cache()->create_count());
640}
641
642TEST(HttpCache, SimpleGET_LoadBypassCache) {
643 MockHttpCache cache;
644
645 // write to the cache
646 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
647
648 // force this transaction to write to the cache again
649 MockTransaction transaction(kSimpleGET_Transaction);
650 transaction.load_flags |= net::LOAD_BYPASS_CACHE;
651
652 RunTransactionTest(cache.http_cache(), transaction);
653
654 EXPECT_EQ(2, cache.network_layer()->transaction_count());
655 EXPECT_EQ(0, cache.disk_cache()->open_count());
656 EXPECT_EQ(2, cache.disk_cache()->create_count());
657}
658
659TEST(HttpCache, SimpleGET_LoadBypassCache_Implicit) {
660 MockHttpCache cache;
661
662 // write to the cache
663 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
664
665 // force this transaction to write to the cache again
666 MockTransaction transaction(kSimpleGET_Transaction);
667 transaction.request_headers = "pragma: no-cache";
668
669 RunTransactionTest(cache.http_cache(), transaction);
670
671 EXPECT_EQ(2, cache.network_layer()->transaction_count());
672 EXPECT_EQ(0, cache.disk_cache()->open_count());
673 EXPECT_EQ(2, cache.disk_cache()->create_count());
674}
675
676TEST(HttpCache, SimpleGET_LoadBypassCache_Implicit2) {
677 MockHttpCache cache;
678
679 // write to the cache
680 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
681
682 // force this transaction to write to the cache again
683 MockTransaction transaction(kSimpleGET_Transaction);
684 transaction.request_headers = "cache-control: no-cache";
685
686 RunTransactionTest(cache.http_cache(), transaction);
687
688 EXPECT_EQ(2, cache.network_layer()->transaction_count());
689 EXPECT_EQ(0, cache.disk_cache()->open_count());
690 EXPECT_EQ(2, cache.disk_cache()->create_count());
691}
692
693TEST(HttpCache, SimpleGET_LoadValidateCache) {
694 MockHttpCache cache;
695
696 // write to the cache
697 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
698
699 // read from the cache
700 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
701
702 // force this transaction to validate the cache
703 MockTransaction transaction(kSimpleGET_Transaction);
704 transaction.load_flags |= net::LOAD_VALIDATE_CACHE;
705
706 RunTransactionTest(cache.http_cache(), transaction);
707
708 EXPECT_EQ(2, cache.network_layer()->transaction_count());
709 EXPECT_EQ(1, cache.disk_cache()->open_count());
710 EXPECT_EQ(1, cache.disk_cache()->create_count());
711}
712
713TEST(HttpCache, SimpleGET_LoadValidateCache_Implicit) {
714 MockHttpCache cache;
715
716 // write to the cache
717 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
718
719 // read from the cache
720 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
721
722 // force this transaction to validate the cache
723 MockTransaction transaction(kSimpleGET_Transaction);
724 transaction.request_headers = "cache-control: max-age=0";
725
726 RunTransactionTest(cache.http_cache(), transaction);
727
728 EXPECT_EQ(2, cache.network_layer()->transaction_count());
729 EXPECT_EQ(1, cache.disk_cache()->open_count());
730 EXPECT_EQ(1, cache.disk_cache()->create_count());
731}
732
[email protected]cad155b2008-09-23 14:44:27733struct Context {
734 int result;
735 TestCompletionCallback callback;
[email protected]af4876d2008-10-21 23:10:57736 scoped_ptr<net::HttpTransaction> trans;
[email protected]cad155b2008-09-23 14:44:27737
738 Context(net::HttpTransaction* t) : result(net::ERR_IO_PENDING), trans(t) {
739 }
740};
741
initial.commit586acc5fe2008-07-26 22:42:52742TEST(HttpCache, SimpleGET_ManyReaders) {
743 MockHttpCache cache;
744
745 MockHttpRequest request(kSimpleGET_Transaction);
746
initial.commit586acc5fe2008-07-26 22:42:52747 std::vector<Context*> context_list;
748 const int kNumTransactions = 5;
749
750 for (int i = 0; i < kNumTransactions; ++i) {
751 context_list.push_back(
752 new Context(cache.http_cache()->CreateTransaction()));
753
754 Context* c = context_list[i];
755 int rv = c->trans->Start(&request, &c->callback);
756 if (rv != net::ERR_IO_PENDING)
757 c->result = rv;
758 }
759
760 // the first request should be a writer at this point, and the subsequent
761 // requests should be pending.
762
763 EXPECT_EQ(1, cache.network_layer()->transaction_count());
764 EXPECT_EQ(0, cache.disk_cache()->open_count());
765 EXPECT_EQ(1, cache.disk_cache()->create_count());
766
767 for (int i = 0; i < kNumTransactions; ++i) {
768 Context* c = context_list[i];
769 if (c->result == net::ERR_IO_PENDING)
770 c->result = c->callback.WaitForResult();
[email protected]af4876d2008-10-21 23:10:57771 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
initial.commit586acc5fe2008-07-26 22:42:52772 }
773
774 // we should not have had to re-open the disk entry
775
776 EXPECT_EQ(1, cache.network_layer()->transaction_count());
777 EXPECT_EQ(0, cache.disk_cache()->open_count());
778 EXPECT_EQ(1, cache.disk_cache()->create_count());
779
780 for (int i = 0; i < kNumTransactions; ++i) {
781 Context* c = context_list[i];
initial.commit586acc5fe2008-07-26 22:42:52782 delete c;
783 }
784}
785
[email protected]e1891642009-01-07 18:30:57786// This is a test for http://code.google.com/p/chromium/issues/detail?id=4769.
787// If cancelling a request is racing with another request for the same resource
788// finishing, we have to make sure that we remove both transactions from the
789// entry.
790TEST(HttpCache, SimpleGET_RacingReaders) {
791 MockHttpCache cache;
792
793 MockHttpRequest request(kSimpleGET_Transaction);
794 MockHttpRequest reader_request(kSimpleGET_Transaction);
795 reader_request.load_flags = net::LOAD_ONLY_FROM_CACHE;
796
797 std::vector<Context*> context_list;
798 const int kNumTransactions = 5;
799
800 for (int i = 0; i < kNumTransactions; ++i) {
801 context_list.push_back(
802 new Context(cache.http_cache()->CreateTransaction()));
803
804 Context* c = context_list[i];
805 MockHttpRequest* this_request = &request;
806 if (i == 1 || i == 2)
807 this_request = &reader_request;
808
809 int rv = c->trans->Start(this_request, &c->callback);
810 if (rv != net::ERR_IO_PENDING)
811 c->result = rv;
812 }
813
814 // The first request should be a writer at this point, and the subsequent
815 // requests should be pending.
816
817 EXPECT_EQ(1, cache.network_layer()->transaction_count());
818 EXPECT_EQ(0, cache.disk_cache()->open_count());
819 EXPECT_EQ(1, cache.disk_cache()->create_count());
820
821 Context* c = context_list[0];
822 ASSERT_EQ(net::ERR_IO_PENDING, c->result);
823 c->result = c->callback.WaitForResult();
824 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
825
826 // Now we have 2 active readers and two queued transactions.
827
828 c = context_list[1];
829 ASSERT_EQ(net::ERR_IO_PENDING, c->result);
830 c->result = c->callback.WaitForResult();
831 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
832
833 // At this point we have one reader, two pending transactions and a task on
834 // the queue to move to the next transaction. Now we cancel the request that
835 // is the current reader, and expect the queued task to be able to start the
836 // next request.
837
838 c = context_list[2];
839 c->trans.reset();
840
841 for (int i = 3; i < kNumTransactions; ++i) {
842 Context* c = context_list[i];
843 if (c->result == net::ERR_IO_PENDING)
844 c->result = c->callback.WaitForResult();
845 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
846 }
847
848 // We should not have had to re-open the disk entry.
849
850 EXPECT_EQ(1, cache.network_layer()->transaction_count());
851 EXPECT_EQ(0, cache.disk_cache()->open_count());
852 EXPECT_EQ(1, cache.disk_cache()->create_count());
853
854 for (int i = 0; i < kNumTransactions; ++i) {
855 Context* c = context_list[i];
856 delete c;
857 }
858}
859
[email protected]b367d9a52009-02-27 01:02:51860// This is a test for http://code.google.com/p/chromium/issues/detail?id=4731.
861// We may attempt to delete an entry synchronously with the act of adding a new
862// transaction to said entry.
863TEST(HttpCache, FastNoStoreGET_DoneWithPending) {
864 MockHttpCache cache;
865
866 // The headers will be served right from the call to Start() the request.
867 MockHttpRequest request(kFastNoStoreGET_Transaction);
868 FastTransactionServer request_handler;
869 AddMockTransaction(&kFastNoStoreGET_Transaction);
870
871 std::vector<Context*> context_list;
872 const int kNumTransactions = 3;
873
874 for (int i = 0; i < kNumTransactions; ++i) {
875 context_list.push_back(
876 new Context(cache.http_cache()->CreateTransaction()));
877
878 Context* c = context_list[i];
879 int rv = c->trans->Start(&request, &c->callback);
880 if (rv != net::ERR_IO_PENDING)
881 c->result = rv;
882 }
883
884 // The first request should be a writer at this point, and the subsequent
885 // requests should be pending.
886
887 EXPECT_EQ(1, cache.network_layer()->transaction_count());
888 EXPECT_EQ(0, cache.disk_cache()->open_count());
889 EXPECT_EQ(1, cache.disk_cache()->create_count());
890
891 // Now, make sure that the second request asks for the entry not to be stored.
892 request_handler.set_no_store(true);
893
894 for (int i = 0; i < kNumTransactions; ++i) {
895 Context* c = context_list[i];
896 if (c->result == net::ERR_IO_PENDING)
897 c->result = c->callback.WaitForResult();
898 ReadAndVerifyTransaction(c->trans.get(), kFastNoStoreGET_Transaction);
899 delete c;
900 }
901
902 EXPECT_EQ(3, cache.network_layer()->transaction_count());
903 EXPECT_EQ(0, cache.disk_cache()->open_count());
904 EXPECT_EQ(2, cache.disk_cache()->create_count());
905
906 RemoveMockTransaction(&kFastNoStoreGET_Transaction);
907}
908
initial.commit586acc5fe2008-07-26 22:42:52909TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
910 MockHttpCache cache;
911
912 MockHttpRequest request(kSimpleGET_Transaction);
913
initial.commit586acc5fe2008-07-26 22:42:52914 std::vector<Context*> context_list;
915 const int kNumTransactions = 2;
916
917 for (int i = 0; i < kNumTransactions; ++i) {
918 context_list.push_back(
919 new Context(cache.http_cache()->CreateTransaction()));
920
921 Context* c = context_list[i];
922 int rv = c->trans->Start(&request, &c->callback);
923 if (rv != net::ERR_IO_PENDING)
924 c->result = rv;
925 }
926
927 // the first request should be a writer at this point, and the subsequent
928 // requests should be pending.
929
930 EXPECT_EQ(1, cache.network_layer()->transaction_count());
931 EXPECT_EQ(0, cache.disk_cache()->open_count());
932 EXPECT_EQ(1, cache.disk_cache()->create_count());
933
934 for (int i = 0; i < kNumTransactions; ++i) {
935 Context* c = context_list[i];
936 if (c->result == net::ERR_IO_PENDING)
937 c->result = c->callback.WaitForResult();
938 // destroy only the first transaction
939 if (i == 0) {
initial.commit586acc5fe2008-07-26 22:42:52940 delete c;
941 context_list[i] = NULL;
942 }
943 }
944
945 // complete the rest of the transactions
946 for (int i = 1; i < kNumTransactions; ++i) {
947 Context* c = context_list[i];
[email protected]af4876d2008-10-21 23:10:57948 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
initial.commit586acc5fe2008-07-26 22:42:52949 }
950
951 // we should have had to re-open the disk entry
952
953 EXPECT_EQ(2, cache.network_layer()->transaction_count());
954 EXPECT_EQ(0, cache.disk_cache()->open_count());
955 EXPECT_EQ(2, cache.disk_cache()->create_count());
956
957 for (int i = 1; i < kNumTransactions; ++i) {
958 Context* c = context_list[i];
initial.commit586acc5fe2008-07-26 22:42:52959 delete c;
960 }
961}
962
963TEST(HttpCache, SimpleGET_AbandonedCacheRead) {
964 MockHttpCache cache;
965
966 // write to the cache
967 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
968
969 MockHttpRequest request(kSimpleGET_Transaction);
970 TestCompletionCallback callback;
971
[email protected]af4876d2008-10-21 23:10:57972 scoped_ptr<net::HttpTransaction> trans(
973 cache.http_cache()->CreateTransaction());
initial.commit586acc5fe2008-07-26 22:42:52974 int rv = trans->Start(&request, &callback);
975 if (rv == net::ERR_IO_PENDING)
976 rv = callback.WaitForResult();
977 ASSERT_EQ(net::OK, rv);
978
[email protected]9dea9e1f2009-01-29 00:30:47979 scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(256);
980 rv = trans->Read(buf, 256, &callback);
initial.commit586acc5fe2008-07-26 22:42:52981 EXPECT_EQ(net::ERR_IO_PENDING, rv);
982
983 // Test that destroying the transaction while it is reading from the cache
984 // works properly.
[email protected]af4876d2008-10-21 23:10:57985 trans.reset();
initial.commit586acc5fe2008-07-26 22:42:52986
987 // Make sure we pump any pending events, which should include a call to
988 // HttpCache::Transaction::OnCacheReadCompleted.
[email protected]295039bd2008-08-15 04:32:57989 MessageLoop::current()->RunAllPending();
initial.commit586acc5fe2008-07-26 22:42:52990}
991
992TEST(HttpCache, TypicalGET_ConditionalRequest) {
993 MockHttpCache cache;
994
995 // write to the cache
996 RunTransactionTest(cache.http_cache(), kTypicalGET_Transaction);
997
998 EXPECT_EQ(1, cache.network_layer()->transaction_count());
999 EXPECT_EQ(0, cache.disk_cache()->open_count());
1000 EXPECT_EQ(1, cache.disk_cache()->create_count());
1001
1002 // get the same URL again, but this time we expect it to result
1003 // in a conditional request.
1004 RunTransactionTest(cache.http_cache(), kTypicalGET_Transaction);
1005
1006 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1007 EXPECT_EQ(1, cache.disk_cache()->open_count());
1008 EXPECT_EQ(1, cache.disk_cache()->create_count());
1009}
1010
1011static void ETagGet_ConditionalRequest_Handler(
1012 const net::HttpRequestInfo* request,
1013 std::string* response_status,
1014 std::string* response_headers,
1015 std::string* response_data) {
[email protected]72d1e592009-03-10 17:39:461016 EXPECT_TRUE(request->extra_headers.find("If-None-Match") !=
1017 std::string::npos);
initial.commit586acc5fe2008-07-26 22:42:521018 response_status->assign("HTTP/1.1 304 Not Modified");
1019 response_headers->assign(kETagGET_Transaction.response_headers);
1020 response_data->clear();
1021}
1022
1023TEST(HttpCache, ETagGET_ConditionalRequest_304) {
1024 MockHttpCache cache;
1025
1026 ScopedMockTransaction transaction(kETagGET_Transaction);
1027
1028 // write to the cache
1029 RunTransactionTest(cache.http_cache(), transaction);
1030
1031 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1032 EXPECT_EQ(0, cache.disk_cache()->open_count());
1033 EXPECT_EQ(1, cache.disk_cache()->create_count());
1034
1035 // get the same URL again, but this time we expect it to result
1036 // in a conditional request.
1037 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
1038 transaction.handler = ETagGet_ConditionalRequest_Handler;
1039 RunTransactionTest(cache.http_cache(), transaction);
1040
1041 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1042 EXPECT_EQ(1, cache.disk_cache()->open_count());
1043 EXPECT_EQ(1, cache.disk_cache()->create_count());
1044}
1045
[email protected]b7d05ab2008-12-09 19:18:411046static void ETagGet_ConditionalRequest_NoStore_Handler(
1047 const net::HttpRequestInfo* request,
1048 std::string* response_status,
1049 std::string* response_headers,
1050 std::string* response_data) {
1051 EXPECT_TRUE(request->extra_headers.find("If-None-Match") !=
1052 std::string::npos);
1053 response_status->assign("HTTP/1.1 304 Not Modified");
1054 response_headers->assign("Cache-Control: no-store\n");
1055 response_data->clear();
1056}
1057
1058TEST(HttpCache, ETagGET_ConditionalRequest_304_NoStore) {
1059 MockHttpCache cache;
1060
1061 ScopedMockTransaction transaction(kETagGET_Transaction);
1062
1063 // Write to the cache.
1064 RunTransactionTest(cache.http_cache(), transaction);
1065
1066 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1067 EXPECT_EQ(0, cache.disk_cache()->open_count());
1068 EXPECT_EQ(1, cache.disk_cache()->create_count());
1069
1070 // Get the same URL again, but this time we expect it to result
1071 // in a conditional request.
1072 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
1073 transaction.handler = ETagGet_ConditionalRequest_NoStore_Handler;
1074 RunTransactionTest(cache.http_cache(), transaction);
1075
1076 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1077 EXPECT_EQ(1, cache.disk_cache()->open_count());
1078 EXPECT_EQ(1, cache.disk_cache()->create_count());
1079
1080 ScopedMockTransaction transaction2(kETagGET_Transaction);
1081
1082 // Write to the cache again. This should create a new entry.
1083 RunTransactionTest(cache.http_cache(), transaction2);
1084
1085 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1086 EXPECT_EQ(1, cache.disk_cache()->open_count());
1087 EXPECT_EQ(2, cache.disk_cache()->create_count());
1088}
1089
initial.commit586acc5fe2008-07-26 22:42:521090TEST(HttpCache, SimplePOST_SkipsCache) {
1091 MockHttpCache cache;
1092
[email protected]96bac982009-03-24 18:20:061093 // Test that we skip the cache for POST requests that do not have an upload
1094 // identifier.
initial.commit586acc5fe2008-07-26 22:42:521095
1096 RunTransactionTest(cache.http_cache(), kSimplePOST_Transaction);
1097
1098 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1099 EXPECT_EQ(0, cache.disk_cache()->open_count());
1100 EXPECT_EQ(0, cache.disk_cache()->create_count());
1101}
1102
1103TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Miss) {
1104 MockHttpCache cache;
1105
1106 // Test that we skip the cache for POST requests. Eventually, we will want
1107 // to cache these, but we'll still have cases where skipping the cache makes
1108 // sense, so we want to make sure that it works properly.
1109
1110 MockTransaction transaction(kSimplePOST_Transaction);
1111 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
1112
1113 MockHttpRequest request(transaction);
1114 TestCompletionCallback callback;
1115
[email protected]af4876d2008-10-21 23:10:571116 scoped_ptr<net::HttpTransaction> trans(
1117 cache.http_cache()->CreateTransaction());
1118 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:521119
1120 int rv = trans->Start(&request, &callback);
1121 if (rv == net::ERR_IO_PENDING)
1122 rv = callback.WaitForResult();
1123 ASSERT_EQ(net::ERR_CACHE_MISS, rv);
1124
[email protected]af4876d2008-10-21 23:10:571125 trans.reset();
initial.commit586acc5fe2008-07-26 22:42:521126
1127 EXPECT_EQ(0, cache.network_layer()->transaction_count());
1128 EXPECT_EQ(0, cache.disk_cache()->open_count());
1129 EXPECT_EQ(0, cache.disk_cache()->create_count());
1130}
1131
[email protected]96bac982009-03-24 18:20:061132TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Hit) {
1133 MockHttpCache cache;
1134
1135 // Test that we hit the cache for POST requests.
1136
1137 MockTransaction transaction(kSimplePOST_Transaction);
1138
1139 const int64 kUploadId = 1; // Just a dummy value.
1140
1141 MockHttpRequest request(transaction);
1142 request.upload_data = new net::UploadData();
1143 request.upload_data->set_identifier(kUploadId);
1144 request.upload_data->AppendBytes("hello", 5);
1145
1146 // Populate the cache.
[email protected]95792eb12009-06-22 21:30:401147 RunTransactionTestWithRequest(cache.http_cache(), transaction, request, NULL);
[email protected]96bac982009-03-24 18:20:061148
1149 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1150 EXPECT_EQ(0, cache.disk_cache()->open_count());
1151 EXPECT_EQ(1, cache.disk_cache()->create_count());
1152
1153 // Load from cache.
1154 request.load_flags |= net::LOAD_ONLY_FROM_CACHE;
[email protected]95792eb12009-06-22 21:30:401155 RunTransactionTestWithRequest(cache.http_cache(), transaction, request, NULL);
[email protected]96bac982009-03-24 18:20:061156
1157 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1158 EXPECT_EQ(1, cache.disk_cache()->open_count());
1159 EXPECT_EQ(1, cache.disk_cache()->create_count());
1160}
1161
initial.commit586acc5fe2008-07-26 22:42:521162TEST(HttpCache, RangeGET_SkipsCache) {
1163 MockHttpCache cache;
1164
[email protected]8bf26f49a2009-06-12 17:35:501165 // Test that we skip the cache for range GET requests. Eventually, we will
1166 // want to cache these, but we'll still have cases where skipping the cache
1167 // makes sense, so we want to make sure that it works properly.
initial.commit586acc5fe2008-07-26 22:42:521168
1169 RunTransactionTest(cache.http_cache(), kRangeGET_Transaction);
1170
1171 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1172 EXPECT_EQ(0, cache.disk_cache()->open_count());
1173 EXPECT_EQ(0, cache.disk_cache()->create_count());
1174
1175 MockTransaction transaction(kSimpleGET_Transaction);
1176 transaction.request_headers = "If-None-Match: foo";
1177 RunTransactionTest(cache.http_cache(), transaction);
1178
1179 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1180 EXPECT_EQ(0, cache.disk_cache()->open_count());
1181 EXPECT_EQ(0, cache.disk_cache()->create_count());
1182
[email protected]72d1e592009-03-10 17:39:461183 transaction.request_headers =
1184 "If-Modified-Since: Wed, 28 Nov 2007 00:45:20 GMT";
initial.commit586acc5fe2008-07-26 22:42:521185 RunTransactionTest(cache.http_cache(), transaction);
1186
1187 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1188 EXPECT_EQ(0, cache.disk_cache()->open_count());
1189 EXPECT_EQ(0, cache.disk_cache()->create_count());
1190}
1191
[email protected]7ee4c4072009-06-30 18:49:471192TEST(HttpCache, GET_Crazy206) {
1193 MockHttpCache cache;
1194 AddMockTransaction(&kRangeGET_TransactionOK);
1195
1196 // Test that receiving 206 for a regular request is handled correctly.
1197
1198 // Write to the cache.
1199 MockTransaction transaction(kRangeGET_TransactionOK);
1200 transaction.request_headers = "";
1201 RunTransactionTest(cache.http_cache(), transaction);
1202
1203 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1204 EXPECT_EQ(0, cache.disk_cache()->open_count());
1205 EXPECT_EQ(1, cache.disk_cache()->create_count());
1206
1207 // This should read again from the net.
1208 RunTransactionTest(cache.http_cache(), transaction);
1209
1210 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1211 EXPECT_EQ(1, cache.disk_cache()->open_count());
1212 EXPECT_EQ(1, cache.disk_cache()->create_count());
1213 RemoveMockTransaction(&kRangeGET_TransactionOK);
1214}
1215
[email protected]8bf26f49a2009-06-12 17:35:501216TEST(HttpCache, DISABLED_RangeGET_OK) {
1217 MockHttpCache cache;
1218 AddMockTransaction(&kRangeGET_TransactionOK);
1219
1220 // Test that we can cache range requests and fetch random blocks from the
1221 // cache and the network.
1222
[email protected]95792eb12009-06-22 21:30:401223 std::string headers;
[email protected]8bf26f49a2009-06-12 17:35:501224
[email protected]95792eb12009-06-22 21:30:401225 // Write to the cache (40-49).
1226 RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK,
1227 &headers);
1228
1229 EXPECT_TRUE(Verify206Response(headers, 40, 49));
[email protected]8bf26f49a2009-06-12 17:35:501230 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1231 EXPECT_EQ(0, cache.disk_cache()->open_count());
1232 EXPECT_EQ(1, cache.disk_cache()->create_count());
1233
1234 // Read from the cache (40-49).
[email protected]95792eb12009-06-22 21:30:401235 RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK,
1236 &headers);
[email protected]8bf26f49a2009-06-12 17:35:501237
[email protected]95792eb12009-06-22 21:30:401238 EXPECT_TRUE(Verify206Response(headers, 40, 49));
[email protected]8bf26f49a2009-06-12 17:35:501239 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1240 EXPECT_EQ(1, cache.disk_cache()->open_count());
1241 EXPECT_EQ(1, cache.disk_cache()->create_count());
1242
1243 // Make sure we are done with the previous transaction.
1244 MessageLoop::current()->RunAllPending();
1245
1246 // Write to the cache (30-39).
1247 MockTransaction transaction(kRangeGET_TransactionOK);
1248 transaction.request_headers = "Range: bytes = 30-39\r\n";
1249 transaction.data = "rg: 30-39 ";
[email protected]95792eb12009-06-22 21:30:401250 RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
[email protected]8bf26f49a2009-06-12 17:35:501251
[email protected]95792eb12009-06-22 21:30:401252 EXPECT_TRUE(Verify206Response(headers, 30, 39));
[email protected]8bf26f49a2009-06-12 17:35:501253 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1254 EXPECT_EQ(2, cache.disk_cache()->open_count());
1255 EXPECT_EQ(1, cache.disk_cache()->create_count());
1256
1257 // Make sure we are done with the previous transaction.
1258 MessageLoop::current()->RunAllPending();
1259
1260 // Write and read from the cache (20-59).
1261 transaction.request_headers = "Range: bytes = 20-59\r\n";
1262 transaction.data = "rg: 20-29 rg: 30-39 rg: 40-49 rg: 50-59 ";
[email protected]95792eb12009-06-22 21:30:401263 RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
[email protected]8bf26f49a2009-06-12 17:35:501264
[email protected]95792eb12009-06-22 21:30:401265 EXPECT_TRUE(Verify206Response(headers, 20, 59));
[email protected]8bf26f49a2009-06-12 17:35:501266 EXPECT_EQ(6, cache.network_layer()->transaction_count());
1267 EXPECT_EQ(3, cache.disk_cache()->open_count());
1268 EXPECT_EQ(1, cache.disk_cache()->create_count());
1269
1270 RemoveMockTransaction(&kRangeGET_TransactionOK);
1271}
1272
[email protected]67fe45c2009-06-24 17:44:571273TEST(HttpCache, DISABLED_UnknownRangeGET_1) {
1274 MockHttpCache cache;
1275 AddMockTransaction(&kRangeGET_TransactionOK);
1276
1277 // Test that we can cache range requests when the start or end is unknown.
1278 // We start with one suffix request, followed by a request from a given point.
1279
1280 std::string headers;
1281
1282 // Write to the cache (70-79).
1283 MockTransaction transaction(kRangeGET_TransactionOK);
1284 transaction.request_headers = "Range: bytes = -10\r\n";
1285 transaction.data = "rg: 70-79 ";
1286 RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
1287
1288 EXPECT_TRUE(Verify206Response(headers, 70, 79));
1289 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1290 EXPECT_EQ(0, cache.disk_cache()->open_count());
1291 EXPECT_EQ(1, cache.disk_cache()->create_count());
1292
1293 // Make sure we are done with the previous transaction.
1294 MessageLoop::current()->RunAllPending();
1295
1296 // Write and read from the cache (60-79).
1297 transaction.request_headers = "Range: bytes = 60-\r\n";
1298 transaction.data = "rg: 60-69 rg: 70-79 ";
1299 RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
1300
1301 EXPECT_TRUE(Verify206Response(headers, 60, 79));
1302 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1303 EXPECT_EQ(1, cache.disk_cache()->open_count());
1304 EXPECT_EQ(1, cache.disk_cache()->create_count());
1305
1306 RemoveMockTransaction(&kRangeGET_TransactionOK);
1307}
1308
1309TEST(HttpCache, DISABLED_UnknownRangeGET_2) {
1310 MockHttpCache cache;
1311 AddMockTransaction(&kRangeGET_TransactionOK);
1312
1313 // Test that we can cache range requests when the start or end is unknown.
1314 // We start with one request from a given point, followed by a suffix request.
1315
1316 std::string headers;
1317
1318 // Write to the cache (70-79).
1319 MockTransaction transaction(kRangeGET_TransactionOK);
1320 transaction.request_headers = "Range: bytes = 70-\r\n";
1321 transaction.data = "rg: 70-79 ";
1322 RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
1323
1324 EXPECT_TRUE(Verify206Response(headers, 70, 79));
1325 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1326 EXPECT_EQ(0, cache.disk_cache()->open_count());
1327 EXPECT_EQ(1, cache.disk_cache()->create_count());
1328
1329 // Make sure we are done with the previous transaction.
1330 MessageLoop::current()->RunAllPending();
1331
1332 // Write and read from the cache (60-79).
1333 transaction.request_headers = "Range: bytes = -20\r\n";
1334 transaction.data = "rg: 60-69 rg: 70-79 ";
1335 RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers);
1336
1337 EXPECT_TRUE(Verify206Response(headers, 60, 79));
1338 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1339 EXPECT_EQ(1, cache.disk_cache()->open_count());
1340 EXPECT_EQ(1, cache.disk_cache()->create_count());
1341
1342 RemoveMockTransaction(&kRangeGET_TransactionOK);
1343}
1344
initial.commit586acc5fe2008-07-26 22:42:521345TEST(HttpCache, SyncRead) {
1346 MockHttpCache cache;
1347
1348 // This test ensures that a read that completes synchronously does not cause
1349 // any problems.
1350
1351 ScopedMockTransaction transaction(kSimpleGET_Transaction);
1352 transaction.test_mode |= (TEST_MODE_SYNC_CACHE_START |
1353 TEST_MODE_SYNC_CACHE_READ);
1354
1355 MockHttpRequest r1(transaction),
1356 r2(transaction),
1357 r3(transaction);
1358
1359 TestTransactionConsumer c1(cache.http_cache()),
1360 c2(cache.http_cache()),
1361 c3(cache.http_cache());
1362
1363 c1.Start(&r1);
1364
1365 r2.load_flags |= net::LOAD_ONLY_FROM_CACHE;
1366 c2.Start(&r2);
1367
1368 r3.load_flags |= net::LOAD_ONLY_FROM_CACHE;
1369 c3.Start(&r3);
1370
1371 MessageLoop::current()->Run();
1372
1373 EXPECT_TRUE(c1.is_done());
1374 EXPECT_TRUE(c2.is_done());
1375 EXPECT_TRUE(c3.is_done());
1376
1377 EXPECT_EQ(net::OK, c1.error());
1378 EXPECT_EQ(net::OK, c2.error());
1379 EXPECT_EQ(net::OK, c3.error());
1380}
1381
1382TEST(HttpCache, ValidationResultsIn200) {
1383 MockHttpCache cache;
1384
1385 // This test ensures that a conditional request, which results in a 200
1386 // instead of a 304, properly truncates the existing response data.
1387
1388 // write to the cache
1389 RunTransactionTest(cache.http_cache(), kETagGET_Transaction);
1390
1391 // force this transaction to validate the cache
1392 MockTransaction transaction(kETagGET_Transaction);
1393 transaction.load_flags |= net::LOAD_VALIDATE_CACHE;
1394 RunTransactionTest(cache.http_cache(), transaction);
1395
1396 // read from the cache
1397 RunTransactionTest(cache.http_cache(), kETagGET_Transaction);
1398}
1399
1400TEST(HttpCache, CachedRedirect) {
1401 MockHttpCache cache;
1402
1403 ScopedMockTransaction kTestTransaction(kSimpleGET_Transaction);
1404 kTestTransaction.status = "HTTP/1.1 301 Moved Permanently";
1405 kTestTransaction.response_headers = "Location: http://www.bar.com/\n";
1406
1407 MockHttpRequest request(kTestTransaction);
1408 TestCompletionCallback callback;
1409
1410 // write to the cache
1411 {
[email protected]af4876d2008-10-21 23:10:571412 scoped_ptr<net::HttpTransaction> trans(
1413 cache.http_cache()->CreateTransaction());
1414 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:521415
1416 int rv = trans->Start(&request, &callback);
1417 if (rv == net::ERR_IO_PENDING)
1418 rv = callback.WaitForResult();
1419 ASSERT_EQ(net::OK, rv);
1420
1421 const net::HttpResponseInfo* info = trans->GetResponseInfo();
1422 ASSERT_TRUE(info);
1423
1424 EXPECT_EQ(info->headers->response_code(), 301);
1425
1426 std::string location;
1427 info->headers->EnumerateHeader(NULL, "Location", &location);
1428 EXPECT_EQ(location, "http://www.bar.com/");
1429
[email protected]af4876d2008-10-21 23:10:571430 // Destroy transaction when going out of scope. We have not actually
1431 // read the response body -- want to test that it is still getting cached.
initial.commit586acc5fe2008-07-26 22:42:521432 }
1433 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1434 EXPECT_EQ(0, cache.disk_cache()->open_count());
1435 EXPECT_EQ(1, cache.disk_cache()->create_count());
1436
1437 // read from the cache
1438 {
[email protected]af4876d2008-10-21 23:10:571439 scoped_ptr<net::HttpTransaction> trans(
1440 cache.http_cache()->CreateTransaction());
1441 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:521442
1443 int rv = trans->Start(&request, &callback);
1444 if (rv == net::ERR_IO_PENDING)
1445 rv = callback.WaitForResult();
1446 ASSERT_EQ(net::OK, rv);
1447
1448 const net::HttpResponseInfo* info = trans->GetResponseInfo();
1449 ASSERT_TRUE(info);
1450
1451 EXPECT_EQ(info->headers->response_code(), 301);
1452
1453 std::string location;
1454 info->headers->EnumerateHeader(NULL, "Location", &location);
1455 EXPECT_EQ(location, "http://www.bar.com/");
1456
[email protected]af4876d2008-10-21 23:10:571457 // Destroy transaction when going out of scope. We have not actually
1458 // read the response body -- want to test that it is still getting cached.
initial.commit586acc5fe2008-07-26 22:42:521459 }
1460 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1461 EXPECT_EQ(1, cache.disk_cache()->open_count());
1462 EXPECT_EQ(1, cache.disk_cache()->create_count());
1463}
1464
1465TEST(HttpCache, CacheControlNoStore) {
1466 MockHttpCache cache;
1467
1468 ScopedMockTransaction transaction(kSimpleGET_Transaction);
1469 transaction.response_headers = "cache-control: no-store\n";
1470
1471 // initial load
1472 RunTransactionTest(cache.http_cache(), transaction);
1473
1474 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1475 EXPECT_EQ(0, cache.disk_cache()->open_count());
1476 EXPECT_EQ(1, cache.disk_cache()->create_count());
1477
1478 // try loading again; it should result in a network fetch
1479 RunTransactionTest(cache.http_cache(), transaction);
1480
1481 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1482 EXPECT_EQ(0, cache.disk_cache()->open_count());
1483 EXPECT_EQ(2, cache.disk_cache()->create_count());
1484
1485 disk_cache::Entry* entry;
1486 bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
1487 EXPECT_FALSE(exists);
1488}
1489
1490TEST(HttpCache, CacheControlNoStore2) {
1491 // this test is similar to the above test, except that the initial response
1492 // is cachable, but when it is validated, no-store is received causing the
1493 // cached document to be deleted.
1494 MockHttpCache cache;
1495
1496 ScopedMockTransaction transaction(kETagGET_Transaction);
1497
1498 // initial load
1499 RunTransactionTest(cache.http_cache(), transaction);
1500
1501 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1502 EXPECT_EQ(0, cache.disk_cache()->open_count());
1503 EXPECT_EQ(1, cache.disk_cache()->create_count());
1504
1505 // try loading again; it should result in a network fetch
1506 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
1507 transaction.response_headers = "cache-control: no-store\n";
1508 RunTransactionTest(cache.http_cache(), transaction);
1509
1510 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1511 EXPECT_EQ(1, cache.disk_cache()->open_count());
1512 EXPECT_EQ(1, cache.disk_cache()->create_count());
1513
1514 disk_cache::Entry* entry;
1515 bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
1516 EXPECT_FALSE(exists);
1517}
1518
1519TEST(HttpCache, CacheControlNoStore3) {
1520 // this test is similar to the above test, except that the response is a 304
1521 // instead of a 200. this should never happen in practice, but it seems like
1522 // a good thing to verify that we still destroy the cache entry.
1523 MockHttpCache cache;
1524
1525 ScopedMockTransaction transaction(kETagGET_Transaction);
1526
1527 // initial load
1528 RunTransactionTest(cache.http_cache(), transaction);
1529
1530 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1531 EXPECT_EQ(0, cache.disk_cache()->open_count());
1532 EXPECT_EQ(1, cache.disk_cache()->create_count());
1533
1534 // try loading again; it should result in a network fetch
1535 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
1536 transaction.response_headers = "cache-control: no-store\n";
1537 transaction.status = "HTTP/1.1 304 Not Modified";
1538 RunTransactionTest(cache.http_cache(), transaction);
1539
1540 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1541 EXPECT_EQ(1, cache.disk_cache()->open_count());
1542 EXPECT_EQ(1, cache.disk_cache()->create_count());
1543
1544 disk_cache::Entry* entry;
1545 bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
1546 EXPECT_FALSE(exists);
1547}
1548
1549// Ensure that we don't cache requests served over bad HTTPS.
1550TEST(HttpCache, SimpleGET_SSLError) {
1551 MockHttpCache cache;
1552
1553 MockTransaction transaction = kSimpleGET_Transaction;
1554 transaction.cert_status = net::CERT_STATUS_REVOKED;
1555 ScopedMockTransaction scoped_transaction(transaction);
1556
1557 // write to the cache
1558 RunTransactionTest(cache.http_cache(), transaction);
1559
1560 // Test that it was not cached.
1561 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
1562
1563 MockHttpRequest request(transaction);
1564 TestCompletionCallback callback;
1565
[email protected]af4876d2008-10-21 23:10:571566 scoped_ptr<net::HttpTransaction> trans(
1567 cache.http_cache()->CreateTransaction());
1568 ASSERT_TRUE(trans.get());
initial.commit586acc5fe2008-07-26 22:42:521569
1570 int rv = trans->Start(&request, &callback);
1571 if (rv == net::ERR_IO_PENDING)
1572 rv = callback.WaitForResult();
1573 ASSERT_EQ(net::ERR_CACHE_MISS, rv);
initial.commit586acc5fe2008-07-26 22:42:521574}
[email protected]3e2d38d2009-02-14 02:01:181575
1576// Ensure that we don't crash by if left-behind transactions.
1577TEST(HttpCache, OutlivedTransactions) {
1578 MockHttpCache* cache = new MockHttpCache;
1579
1580 net::HttpTransaction* trans = cache->http_cache()->CreateTransaction();
[email protected]b367d9a52009-02-27 01:02:511581 delete cache;
[email protected]3e2d38d2009-02-14 02:01:181582 delete trans;
1583}
[email protected]981797002009-06-05 07:14:151584
1585// Test that the disabled mode works.
1586TEST(HttpCache, CacheDisabledMode) {
1587 MockHttpCache cache;
1588
1589 // write to the cache
1590 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
1591
1592 // go into disabled mode
1593 cache.http_cache()->set_mode(net::HttpCache::DISABLE);
1594
1595 // force this transaction to write to the cache again
1596 MockTransaction transaction(kSimpleGET_Transaction);
1597
1598 RunTransactionTest(cache.http_cache(), transaction);
1599
1600 EXPECT_EQ(2, cache.network_layer()->transaction_count());
1601 EXPECT_EQ(0, cache.disk_cache()->open_count());
1602 EXPECT_EQ(1, cache.disk_cache()->create_count());
1603}