blob: 2514f5602006b5cc26adbfee0cac76059aabaee0 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_cache.h"
6
7#include <windows.h>
8
9#include "base/message_loop.h"
10#include "base/string_util.h"
11#include "net/base/net_errors.h"
12#include "net/base/load_flags.h"
13#include "net/disk_cache/disk_cache.h"
14#include "net/http/http_request_info.h"
15#include "net/http/http_response_info.h"
16#include "net/http/http_transaction.h"
17#include "net/http/http_transaction_unittest.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20#pragma warning(disable: 4355)
21
22namespace {
23
24//-----------------------------------------------------------------------------
25// mock disk cache (a very basic memory cache implementation)
26
27class MockDiskEntry : public disk_cache::Entry,
28 public base::RefCounted<MockDiskEntry> {
29 public:
30 MockDiskEntry() : test_mode_(0), doomed_(false) {
31 }
32
33 MockDiskEntry(const std::string& key) : key_(key), doomed_(false) {
34 const MockTransaction* t = FindMockTransaction(GURL(key));
35 DCHECK(t);
36 test_mode_ = t->test_mode;
37 }
38
39 ~MockDiskEntry() {
40 }
41
42 bool is_doomed() const { return doomed_; }
43
44 virtual void Doom() {
45 doomed_ = true;
46 }
47
48 virtual void Close() {
49 Release();
50 }
51
52 virtual std::string GetKey() const {
53 return key_;
54 }
55
56 virtual Time GetLastUsed() const {
57 return Time::FromInternalValue(0);
58 }
59
60 virtual Time GetLastModified() const {
61 return Time::FromInternalValue(0);
62 }
63
64 virtual int32 GetDataSize(int index) const {
65 DCHECK(index >= 0 && index < 2);
66 return static_cast<int32>(data_[index].size());
67 }
68
69 virtual int ReadData(int index, int offset, char* buf, int buf_len,
70 net::CompletionCallback* callback) {
71 DCHECK(index >= 0 && index < 2);
72
73 if (offset < 0 || offset > static_cast<int>(data_[index].size()))
74 return net::ERR_FAILED;
75 if (offset == data_[index].size())
76 return 0;
77
78 int num = std::min(buf_len, static_cast<int>(data_[index].size()) - offset);
79 memcpy(buf, &data_[index][offset], num);
80
81 if (!callback || (test_mode_ & TEST_MODE_SYNC_CACHE_READ))
82 return num;
83
84 CallbackLater(callback, num);
85 return net::ERR_IO_PENDING;
86 }
87
88 virtual int WriteData(int index, int offset, const char* buf, int buf_len,
89 net::CompletionCallback* callback, bool truncate) {
90 DCHECK(index >= 0 && index < 2);
91 DCHECK(truncate);
92
93 if (offset < 0 || offset > static_cast<int>(data_[index].size()))
94 return net::ERR_FAILED;
95
96 data_[index].resize(offset + buf_len);
97 if (buf_len)
98 memcpy(&data_[index][offset], buf, buf_len);
99 return buf_len;
100 }
101
102 private:
103 // Unlike the callbacks for MockHttpTransaction, we want this one to run even
104 // if the consumer called Close on the MockDiskEntry. We achieve that by
105 // leveraging the fact that this class is reference counted.
106 void CallbackLater(net::CompletionCallback* callback, int result) {
107 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
108 &MockDiskEntry::RunCallback, callback, result));
109 }
110 void RunCallback(net::CompletionCallback* callback, int result) {
111 callback->Run(result);
112 }
113
114 std::string key_;
115 std::vector<char> data_[2];
116 int test_mode_;
117 bool doomed_;
118};
119
120class MockDiskCache : public disk_cache::Backend {
121 public:
122 MockDiskCache() : open_count_(0), create_count_(0), fail_requests_(0) {
123 }
124
125 ~MockDiskCache() {
126 EntryMap::iterator it = entries_.begin();
127 for (; it != entries_.end(); ++it)
128 it->second->Release();
129 }
130
131 virtual int32 GetEntryCount() const {
132 return static_cast<int32>(entries_.size());
133 }
134
135 virtual bool OpenEntry(const std::string& key, disk_cache::Entry** entry) {
136 if (fail_requests_)
137 return false;
138
139 EntryMap::iterator it = entries_.find(key);
140 if (it == entries_.end())
141 return false;
142
143 if (it->second->is_doomed()) {
144 it->second->Release();
145 entries_.erase(it);
146 return false;
147 }
148
149 open_count_++;
150
151 it->second->AddRef();
152 *entry = it->second;
153
154 return true;
155 }
156
157 virtual bool CreateEntry(const std::string& key, disk_cache::Entry** entry) {
158 if (fail_requests_)
159 return false;
160
161 EntryMap::iterator it = entries_.find(key);
162 DCHECK(it == entries_.end());
163
164 create_count_++;
165
166 MockDiskEntry* new_entry = new MockDiskEntry(key);
167
168 new_entry->AddRef();
169 entries_[key] = new_entry;
170
171 new_entry->AddRef();
172 *entry = new_entry;
173
174 return true;
175 }
176
177 virtual bool DoomEntry(const std::string& key) {
178 EntryMap::iterator it = entries_.find(key);
179 if (it != entries_.end()) {
180 it->second->Release();
181 entries_.erase(it);
182 }
183 return true;
184 }
185
186 virtual bool DoomAllEntries() {
187 return false;
188 }
189
190 virtual bool DoomEntriesBetween(const Time initial_time,
191 const Time end_time) {
192 return true;
193 }
194
195 virtual bool DoomEntriesSince(const Time initial_time) {
196 return true;
197 }
198
199 virtual bool OpenNextEntry(void** iter, disk_cache::Entry** next_entry) {
200 return false;
201 }
202
203 virtual void EndEnumeration(void** iter) {}
204
205 virtual void GetStats(
206 std::vector<std::pair<std::string, std::string> >* stats) {
207 }
208
209 // returns number of times a cache entry was successfully opened
210 int open_count() const { return open_count_; }
211
212 // returns number of times a cache entry was successfully created
213 int create_count() const { return create_count_; }
214
215 // Fail any subsequent CreateEntry and OpenEntry.
216 void set_fail_requests() { fail_requests_ = true; }
217
218 private:
219 typedef stdext::hash_map<std::string, MockDiskEntry*> EntryMap;
220 EntryMap entries_;
221 int open_count_;
222 int create_count_;
223 bool fail_requests_;
224};
225
226class MockHttpCache {
227 public:
228 MockHttpCache() : http_cache_(new MockNetworkLayer(), new MockDiskCache()) {
229 }
230
231 net::HttpCache* http_cache() { return &http_cache_; }
232
233 MockNetworkLayer* network_layer() {
234 return static_cast<MockNetworkLayer*>(http_cache_.network_layer());
235 }
236 MockDiskCache* disk_cache() {
237 return static_cast<MockDiskCache*>(http_cache_.disk_cache());
238 }
239
240 private:
241 net::HttpCache http_cache_;
242};
243
244
245//-----------------------------------------------------------------------------
246// helpers
247
248void ReadAndVerifyTransaction(net::HttpTransaction* trans,
249 const MockTransaction& trans_info) {
250 std::string content;
251 int rv = ReadTransaction(trans, &content);
252
253 EXPECT_EQ(net::OK, rv);
254 EXPECT_EQ(strlen(trans_info.data), content.size());
255 EXPECT_EQ(0, memcmp(trans_info.data, content.data(), content.size()));
256}
257
258void RunTransactionTest(net::HttpCache* cache,
259 const MockTransaction& trans_info) {
260 MockHttpRequest request(trans_info);
261 TestCompletionCallback callback;
262
263 // write to the cache
264
265 net::HttpTransaction* trans = cache->CreateTransaction();
266 ASSERT_TRUE(trans);
267
268 int rv = trans->Start(&request, &callback);
269 if (rv == net::ERR_IO_PENDING)
270 rv = callback.WaitForResult();
271 ASSERT_EQ(net::OK, rv);
272
273 const net::HttpResponseInfo* response = trans->GetResponseInfo();
274 ASSERT_TRUE(response);
275
276 ReadAndVerifyTransaction(trans, trans_info);
277
278 trans->Destroy();
279}
280
281} // namespace
282
283
284//-----------------------------------------------------------------------------
285// tests
286
287
288TEST(HttpCache, CreateThenDestroy) {
289 MockHttpCache cache;
290
291 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
292 ASSERT_TRUE(trans);
293
294 trans->Destroy();
295}
296
297TEST(HttpCache, SimpleGET) {
298 MockHttpCache cache;
299
300 // write to the cache
301 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
302
303 EXPECT_EQ(1, cache.network_layer()->transaction_count());
304 EXPECT_EQ(0, cache.disk_cache()->open_count());
305 EXPECT_EQ(1, cache.disk_cache()->create_count());
306}
307
308TEST(HttpCache, SimpleGETNoDiskCache) {
309 MockHttpCache cache;
310
311 cache.disk_cache()->set_fail_requests();
312
313 // Read from the network, and don't use the cache.
314 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
315
316 EXPECT_EQ(1, cache.network_layer()->transaction_count());
317 EXPECT_EQ(0, cache.disk_cache()->open_count());
318 EXPECT_EQ(0, cache.disk_cache()->create_count());
319}
320
321TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) {
322 MockHttpCache cache;
323
324 // write to the cache
325 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
326
327 // force this transaction to read from the cache
328 MockTransaction transaction(kSimpleGET_Transaction);
329 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
330
331 RunTransactionTest(cache.http_cache(), transaction);
332
333 EXPECT_EQ(1, cache.network_layer()->transaction_count());
334 EXPECT_EQ(1, cache.disk_cache()->open_count());
335 EXPECT_EQ(1, cache.disk_cache()->create_count());
336}
337
338TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Miss) {
339 MockHttpCache cache;
340
341 // force this transaction to read from the cache
342 MockTransaction transaction(kSimpleGET_Transaction);
343 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
344
345 MockHttpRequest request(transaction);
346 TestCompletionCallback callback;
347
348 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
349 ASSERT_TRUE(trans);
350
351 int rv = trans->Start(&request, &callback);
352 if (rv == net::ERR_IO_PENDING)
353 rv = callback.WaitForResult();
354 ASSERT_EQ(net::ERR_CACHE_MISS, rv);
355
356 trans->Destroy();
357
358 EXPECT_EQ(0, cache.network_layer()->transaction_count());
359 EXPECT_EQ(0, cache.disk_cache()->open_count());
360 EXPECT_EQ(0, cache.disk_cache()->create_count());
361}
362
363TEST(HttpCache, SimpleGET_LoadPreferringCache_Hit) {
364 MockHttpCache cache;
365
366 // write to the cache
367 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
368
369 // force this transaction to read from the cache if valid
370 MockTransaction transaction(kSimpleGET_Transaction);
371 transaction.load_flags |= net::LOAD_PREFERRING_CACHE;
372
373 RunTransactionTest(cache.http_cache(), transaction);
374
375 EXPECT_EQ(1, cache.network_layer()->transaction_count());
376 EXPECT_EQ(1, cache.disk_cache()->open_count());
377 EXPECT_EQ(1, cache.disk_cache()->create_count());
378}
379
380TEST(HttpCache, SimpleGET_LoadPreferringCache_Miss) {
381 MockHttpCache cache;
382
383 // force this transaction to read from the cache if valid
384 MockTransaction transaction(kSimpleGET_Transaction);
385 transaction.load_flags |= net::LOAD_PREFERRING_CACHE;
386
387 RunTransactionTest(cache.http_cache(), transaction);
388
389 EXPECT_EQ(1, cache.network_layer()->transaction_count());
390 EXPECT_EQ(0, cache.disk_cache()->open_count());
391 EXPECT_EQ(1, cache.disk_cache()->create_count());
392}
393
394TEST(HttpCache, SimpleGET_LoadBypassCache) {
395 MockHttpCache cache;
396
397 // write to the cache
398 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
399
400 // force this transaction to write to the cache again
401 MockTransaction transaction(kSimpleGET_Transaction);
402 transaction.load_flags |= net::LOAD_BYPASS_CACHE;
403
404 RunTransactionTest(cache.http_cache(), transaction);
405
406 EXPECT_EQ(2, cache.network_layer()->transaction_count());
407 EXPECT_EQ(0, cache.disk_cache()->open_count());
408 EXPECT_EQ(2, cache.disk_cache()->create_count());
409}
410
411TEST(HttpCache, SimpleGET_LoadBypassCache_Implicit) {
412 MockHttpCache cache;
413
414 // write to the cache
415 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
416
417 // force this transaction to write to the cache again
418 MockTransaction transaction(kSimpleGET_Transaction);
419 transaction.request_headers = "pragma: no-cache";
420
421 RunTransactionTest(cache.http_cache(), transaction);
422
423 EXPECT_EQ(2, cache.network_layer()->transaction_count());
424 EXPECT_EQ(0, cache.disk_cache()->open_count());
425 EXPECT_EQ(2, cache.disk_cache()->create_count());
426}
427
428TEST(HttpCache, SimpleGET_LoadBypassCache_Implicit2) {
429 MockHttpCache cache;
430
431 // write to the cache
432 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
433
434 // force this transaction to write to the cache again
435 MockTransaction transaction(kSimpleGET_Transaction);
436 transaction.request_headers = "cache-control: no-cache";
437
438 RunTransactionTest(cache.http_cache(), transaction);
439
440 EXPECT_EQ(2, cache.network_layer()->transaction_count());
441 EXPECT_EQ(0, cache.disk_cache()->open_count());
442 EXPECT_EQ(2, cache.disk_cache()->create_count());
443}
444
445TEST(HttpCache, SimpleGET_LoadValidateCache) {
446 MockHttpCache cache;
447
448 // write to the cache
449 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
450
451 // read from the cache
452 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
453
454 // force this transaction to validate the cache
455 MockTransaction transaction(kSimpleGET_Transaction);
456 transaction.load_flags |= net::LOAD_VALIDATE_CACHE;
457
458 RunTransactionTest(cache.http_cache(), transaction);
459
460 EXPECT_EQ(2, cache.network_layer()->transaction_count());
461 EXPECT_EQ(1, cache.disk_cache()->open_count());
462 EXPECT_EQ(1, cache.disk_cache()->create_count());
463}
464
465TEST(HttpCache, SimpleGET_LoadValidateCache_Implicit) {
466 MockHttpCache cache;
467
468 // write to the cache
469 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
470
471 // read from the cache
472 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
473
474 // force this transaction to validate the cache
475 MockTransaction transaction(kSimpleGET_Transaction);
476 transaction.request_headers = "cache-control: max-age=0";
477
478 RunTransactionTest(cache.http_cache(), transaction);
479
480 EXPECT_EQ(2, cache.network_layer()->transaction_count());
481 EXPECT_EQ(1, cache.disk_cache()->open_count());
482 EXPECT_EQ(1, cache.disk_cache()->create_count());
483}
484
485TEST(HttpCache, SimpleGET_ManyReaders) {
486 MockHttpCache cache;
487
488 MockHttpRequest request(kSimpleGET_Transaction);
489
490 struct Context {
491 int result;
492 TestCompletionCallback callback;
493 net::HttpTransaction* trans;
494
495 Context(net::HttpTransaction* t) : result(net::ERR_IO_PENDING), trans(t) {
496 }
497 };
498
499 std::vector<Context*> context_list;
500 const int kNumTransactions = 5;
501
502 for (int i = 0; i < kNumTransactions; ++i) {
503 context_list.push_back(
504 new Context(cache.http_cache()->CreateTransaction()));
505
506 Context* c = context_list[i];
507 int rv = c->trans->Start(&request, &c->callback);
508 if (rv != net::ERR_IO_PENDING)
509 c->result = rv;
510 }
511
512 // the first request should be a writer at this point, and the subsequent
513 // requests should be pending.
514
515 EXPECT_EQ(1, cache.network_layer()->transaction_count());
516 EXPECT_EQ(0, cache.disk_cache()->open_count());
517 EXPECT_EQ(1, cache.disk_cache()->create_count());
518
519 for (int i = 0; i < kNumTransactions; ++i) {
520 Context* c = context_list[i];
521 if (c->result == net::ERR_IO_PENDING)
522 c->result = c->callback.WaitForResult();
523 ReadAndVerifyTransaction(c->trans, kSimpleGET_Transaction);
524 }
525
526 // we should not have had to re-open the disk entry
527
528 EXPECT_EQ(1, cache.network_layer()->transaction_count());
529 EXPECT_EQ(0, cache.disk_cache()->open_count());
530 EXPECT_EQ(1, cache.disk_cache()->create_count());
531
532 for (int i = 0; i < kNumTransactions; ++i) {
533 Context* c = context_list[i];
534 c->trans->Destroy();
535 delete c;
536 }
537}
538
539TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
540 MockHttpCache cache;
541
542 MockHttpRequest request(kSimpleGET_Transaction);
543
544 struct Context {
545 int result;
546 TestCompletionCallback callback;
547 net::HttpTransaction* trans;
548
549 Context(net::HttpTransaction* t) : result(net::ERR_IO_PENDING), trans(t) {
550 }
551 };
552
553 std::vector<Context*> context_list;
554 const int kNumTransactions = 2;
555
556 for (int i = 0; i < kNumTransactions; ++i) {
557 context_list.push_back(
558 new Context(cache.http_cache()->CreateTransaction()));
559
560 Context* c = context_list[i];
561 int rv = c->trans->Start(&request, &c->callback);
562 if (rv != net::ERR_IO_PENDING)
563 c->result = rv;
564 }
565
566 // the first request should be a writer at this point, and the subsequent
567 // requests should be pending.
568
569 EXPECT_EQ(1, cache.network_layer()->transaction_count());
570 EXPECT_EQ(0, cache.disk_cache()->open_count());
571 EXPECT_EQ(1, cache.disk_cache()->create_count());
572
573 for (int i = 0; i < kNumTransactions; ++i) {
574 Context* c = context_list[i];
575 if (c->result == net::ERR_IO_PENDING)
576 c->result = c->callback.WaitForResult();
577 // destroy only the first transaction
578 if (i == 0) {
579 c->trans->Destroy();
580 delete c;
581 context_list[i] = NULL;
582 }
583 }
584
585 // complete the rest of the transactions
586 for (int i = 1; i < kNumTransactions; ++i) {
587 Context* c = context_list[i];
588 ReadAndVerifyTransaction(c->trans, kSimpleGET_Transaction);
589 }
590
591 // we should have had to re-open the disk entry
592
593 EXPECT_EQ(2, cache.network_layer()->transaction_count());
594 EXPECT_EQ(0, cache.disk_cache()->open_count());
595 EXPECT_EQ(2, cache.disk_cache()->create_count());
596
597 for (int i = 1; i < kNumTransactions; ++i) {
598 Context* c = context_list[i];
599 c->trans->Destroy();
600 delete c;
601 }
602}
603
604TEST(HttpCache, SimpleGET_AbandonedCacheRead) {
605 MockHttpCache cache;
606
607 // write to the cache
608 RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
609
610 MockHttpRequest request(kSimpleGET_Transaction);
611 TestCompletionCallback callback;
612
613 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
614 int rv = trans->Start(&request, &callback);
615 if (rv == net::ERR_IO_PENDING)
616 rv = callback.WaitForResult();
617 ASSERT_EQ(net::OK, rv);
618
619 char buf[256];
620 rv = trans->Read(buf, sizeof(buf), &callback);
621 EXPECT_EQ(net::ERR_IO_PENDING, rv);
622
623 // Test that destroying the transaction while it is reading from the cache
624 // works properly.
625 trans->Destroy();
626
627 // Make sure we pump any pending events, which should include a call to
628 // HttpCache::Transaction::OnCacheReadCompleted.
[email protected]295039bd2008-08-15 04:32:57629 MessageLoop::current()->RunAllPending();
initial.commit586acc5fe2008-07-26 22:42:52630}
631
632TEST(HttpCache, TypicalGET_ConditionalRequest) {
633 MockHttpCache cache;
634
635 // write to the cache
636 RunTransactionTest(cache.http_cache(), kTypicalGET_Transaction);
637
638 EXPECT_EQ(1, cache.network_layer()->transaction_count());
639 EXPECT_EQ(0, cache.disk_cache()->open_count());
640 EXPECT_EQ(1, cache.disk_cache()->create_count());
641
642 // get the same URL again, but this time we expect it to result
643 // in a conditional request.
644 RunTransactionTest(cache.http_cache(), kTypicalGET_Transaction);
645
646 EXPECT_EQ(2, cache.network_layer()->transaction_count());
647 EXPECT_EQ(1, cache.disk_cache()->open_count());
648 EXPECT_EQ(1, cache.disk_cache()->create_count());
649}
650
651static void ETagGet_ConditionalRequest_Handler(
652 const net::HttpRequestInfo* request,
653 std::string* response_status,
654 std::string* response_headers,
655 std::string* response_data) {
656 EXPECT_TRUE(request->extra_headers.find("If-None-Match") != std::string::npos);
657 response_status->assign("HTTP/1.1 304 Not Modified");
658 response_headers->assign(kETagGET_Transaction.response_headers);
659 response_data->clear();
660}
661
662TEST(HttpCache, ETagGET_ConditionalRequest_304) {
663 MockHttpCache cache;
664
665 ScopedMockTransaction transaction(kETagGET_Transaction);
666
667 // write to the cache
668 RunTransactionTest(cache.http_cache(), transaction);
669
670 EXPECT_EQ(1, cache.network_layer()->transaction_count());
671 EXPECT_EQ(0, cache.disk_cache()->open_count());
672 EXPECT_EQ(1, cache.disk_cache()->create_count());
673
674 // get the same URL again, but this time we expect it to result
675 // in a conditional request.
676 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
677 transaction.handler = ETagGet_ConditionalRequest_Handler;
678 RunTransactionTest(cache.http_cache(), transaction);
679
680 EXPECT_EQ(2, cache.network_layer()->transaction_count());
681 EXPECT_EQ(1, cache.disk_cache()->open_count());
682 EXPECT_EQ(1, cache.disk_cache()->create_count());
683}
684
685TEST(HttpCache, SimplePOST_SkipsCache) {
686 MockHttpCache cache;
687
688 // Test that we skip the cache for POST requests. Eventually, we will want
689 // to cache these, but we'll still have cases where skipping the cache makes
690 // sense, so we want to make sure that it works properly.
691
692 RunTransactionTest(cache.http_cache(), kSimplePOST_Transaction);
693
694 EXPECT_EQ(1, cache.network_layer()->transaction_count());
695 EXPECT_EQ(0, cache.disk_cache()->open_count());
696 EXPECT_EQ(0, cache.disk_cache()->create_count());
697}
698
699TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Miss) {
700 MockHttpCache cache;
701
702 // Test that we skip the cache for POST requests. Eventually, we will want
703 // to cache these, but we'll still have cases where skipping the cache makes
704 // sense, so we want to make sure that it works properly.
705
706 MockTransaction transaction(kSimplePOST_Transaction);
707 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
708
709 MockHttpRequest request(transaction);
710 TestCompletionCallback callback;
711
712 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
713 ASSERT_TRUE(trans);
714
715 int rv = trans->Start(&request, &callback);
716 if (rv == net::ERR_IO_PENDING)
717 rv = callback.WaitForResult();
718 ASSERT_EQ(net::ERR_CACHE_MISS, rv);
719
720 trans->Destroy();
721
722 EXPECT_EQ(0, cache.network_layer()->transaction_count());
723 EXPECT_EQ(0, cache.disk_cache()->open_count());
724 EXPECT_EQ(0, cache.disk_cache()->create_count());
725}
726
727TEST(HttpCache, RangeGET_SkipsCache) {
728 MockHttpCache cache;
729
730 // Test that we skip the cache for POST requests. Eventually, we will want
731 // to cache these, but we'll still have cases where skipping the cache makes
732 // sense, so we want to make sure that it works properly.
733
734 RunTransactionTest(cache.http_cache(), kRangeGET_Transaction);
735
736 EXPECT_EQ(1, cache.network_layer()->transaction_count());
737 EXPECT_EQ(0, cache.disk_cache()->open_count());
738 EXPECT_EQ(0, cache.disk_cache()->create_count());
739
740 MockTransaction transaction(kSimpleGET_Transaction);
741 transaction.request_headers = "If-None-Match: foo";
742 RunTransactionTest(cache.http_cache(), transaction);
743
744 EXPECT_EQ(2, cache.network_layer()->transaction_count());
745 EXPECT_EQ(0, cache.disk_cache()->open_count());
746 EXPECT_EQ(0, cache.disk_cache()->create_count());
747
748 transaction.request_headers = "If-Modified-Since: Wed, 28 Nov 2007 00:45:20 GMT";
749 RunTransactionTest(cache.http_cache(), transaction);
750
751 EXPECT_EQ(3, cache.network_layer()->transaction_count());
752 EXPECT_EQ(0, cache.disk_cache()->open_count());
753 EXPECT_EQ(0, cache.disk_cache()->create_count());
754}
755
756TEST(HttpCache, SyncRead) {
757 MockHttpCache cache;
758
759 // This test ensures that a read that completes synchronously does not cause
760 // any problems.
761
762 ScopedMockTransaction transaction(kSimpleGET_Transaction);
763 transaction.test_mode |= (TEST_MODE_SYNC_CACHE_START |
764 TEST_MODE_SYNC_CACHE_READ);
765
766 MockHttpRequest r1(transaction),
767 r2(transaction),
768 r3(transaction);
769
770 TestTransactionConsumer c1(cache.http_cache()),
771 c2(cache.http_cache()),
772 c3(cache.http_cache());
773
774 c1.Start(&r1);
775
776 r2.load_flags |= net::LOAD_ONLY_FROM_CACHE;
777 c2.Start(&r2);
778
779 r3.load_flags |= net::LOAD_ONLY_FROM_CACHE;
780 c3.Start(&r3);
781
782 MessageLoop::current()->Run();
783
784 EXPECT_TRUE(c1.is_done());
785 EXPECT_TRUE(c2.is_done());
786 EXPECT_TRUE(c3.is_done());
787
788 EXPECT_EQ(net::OK, c1.error());
789 EXPECT_EQ(net::OK, c2.error());
790 EXPECT_EQ(net::OK, c3.error());
791}
792
793TEST(HttpCache, ValidationResultsIn200) {
794 MockHttpCache cache;
795
796 // This test ensures that a conditional request, which results in a 200
797 // instead of a 304, properly truncates the existing response data.
798
799 // write to the cache
800 RunTransactionTest(cache.http_cache(), kETagGET_Transaction);
801
802 // force this transaction to validate the cache
803 MockTransaction transaction(kETagGET_Transaction);
804 transaction.load_flags |= net::LOAD_VALIDATE_CACHE;
805 RunTransactionTest(cache.http_cache(), transaction);
806
807 // read from the cache
808 RunTransactionTest(cache.http_cache(), kETagGET_Transaction);
809}
810
811TEST(HttpCache, CachedRedirect) {
812 MockHttpCache cache;
813
814 ScopedMockTransaction kTestTransaction(kSimpleGET_Transaction);
815 kTestTransaction.status = "HTTP/1.1 301 Moved Permanently";
816 kTestTransaction.response_headers = "Location: http://www.bar.com/\n";
817
818 MockHttpRequest request(kTestTransaction);
819 TestCompletionCallback callback;
820
821 // write to the cache
822 {
823 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
824 ASSERT_TRUE(trans);
825
826 int rv = trans->Start(&request, &callback);
827 if (rv == net::ERR_IO_PENDING)
828 rv = callback.WaitForResult();
829 ASSERT_EQ(net::OK, rv);
830
831 const net::HttpResponseInfo* info = trans->GetResponseInfo();
832 ASSERT_TRUE(info);
833
834 EXPECT_EQ(info->headers->response_code(), 301);
835
836 std::string location;
837 info->headers->EnumerateHeader(NULL, "Location", &location);
838 EXPECT_EQ(location, "http://www.bar.com/");
839
840 // now, destroy the transaction without actually reading the response body.
841 // we want to test that it is still getting cached.
842 trans->Destroy();
843 }
844 EXPECT_EQ(1, cache.network_layer()->transaction_count());
845 EXPECT_EQ(0, cache.disk_cache()->open_count());
846 EXPECT_EQ(1, cache.disk_cache()->create_count());
847
848 // read from the cache
849 {
850 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
851 ASSERT_TRUE(trans);
852
853 int rv = trans->Start(&request, &callback);
854 if (rv == net::ERR_IO_PENDING)
855 rv = callback.WaitForResult();
856 ASSERT_EQ(net::OK, rv);
857
858 const net::HttpResponseInfo* info = trans->GetResponseInfo();
859 ASSERT_TRUE(info);
860
861 EXPECT_EQ(info->headers->response_code(), 301);
862
863 std::string location;
864 info->headers->EnumerateHeader(NULL, "Location", &location);
865 EXPECT_EQ(location, "http://www.bar.com/");
866
867 // now, destroy the transaction without actually reading the response body.
868 // we want to test that it is still getting cached.
869 trans->Destroy();
870 }
871 EXPECT_EQ(1, cache.network_layer()->transaction_count());
872 EXPECT_EQ(1, cache.disk_cache()->open_count());
873 EXPECT_EQ(1, cache.disk_cache()->create_count());
874}
875
876TEST(HttpCache, CacheControlNoStore) {
877 MockHttpCache cache;
878
879 ScopedMockTransaction transaction(kSimpleGET_Transaction);
880 transaction.response_headers = "cache-control: no-store\n";
881
882 // initial load
883 RunTransactionTest(cache.http_cache(), transaction);
884
885 EXPECT_EQ(1, cache.network_layer()->transaction_count());
886 EXPECT_EQ(0, cache.disk_cache()->open_count());
887 EXPECT_EQ(1, cache.disk_cache()->create_count());
888
889 // try loading again; it should result in a network fetch
890 RunTransactionTest(cache.http_cache(), transaction);
891
892 EXPECT_EQ(2, cache.network_layer()->transaction_count());
893 EXPECT_EQ(0, cache.disk_cache()->open_count());
894 EXPECT_EQ(2, cache.disk_cache()->create_count());
895
896 disk_cache::Entry* entry;
897 bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
898 EXPECT_FALSE(exists);
899}
900
901TEST(HttpCache, CacheControlNoStore2) {
902 // this test is similar to the above test, except that the initial response
903 // is cachable, but when it is validated, no-store is received causing the
904 // cached document to be deleted.
905 MockHttpCache cache;
906
907 ScopedMockTransaction transaction(kETagGET_Transaction);
908
909 // initial load
910 RunTransactionTest(cache.http_cache(), transaction);
911
912 EXPECT_EQ(1, cache.network_layer()->transaction_count());
913 EXPECT_EQ(0, cache.disk_cache()->open_count());
914 EXPECT_EQ(1, cache.disk_cache()->create_count());
915
916 // try loading again; it should result in a network fetch
917 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
918 transaction.response_headers = "cache-control: no-store\n";
919 RunTransactionTest(cache.http_cache(), transaction);
920
921 EXPECT_EQ(2, cache.network_layer()->transaction_count());
922 EXPECT_EQ(1, cache.disk_cache()->open_count());
923 EXPECT_EQ(1, cache.disk_cache()->create_count());
924
925 disk_cache::Entry* entry;
926 bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
927 EXPECT_FALSE(exists);
928}
929
930TEST(HttpCache, CacheControlNoStore3) {
931 // this test is similar to the above test, except that the response is a 304
932 // instead of a 200. this should never happen in practice, but it seems like
933 // a good thing to verify that we still destroy the cache entry.
934 MockHttpCache cache;
935
936 ScopedMockTransaction transaction(kETagGET_Transaction);
937
938 // initial load
939 RunTransactionTest(cache.http_cache(), transaction);
940
941 EXPECT_EQ(1, cache.network_layer()->transaction_count());
942 EXPECT_EQ(0, cache.disk_cache()->open_count());
943 EXPECT_EQ(1, cache.disk_cache()->create_count());
944
945 // try loading again; it should result in a network fetch
946 transaction.load_flags = net::LOAD_VALIDATE_CACHE;
947 transaction.response_headers = "cache-control: no-store\n";
948 transaction.status = "HTTP/1.1 304 Not Modified";
949 RunTransactionTest(cache.http_cache(), transaction);
950
951 EXPECT_EQ(2, cache.network_layer()->transaction_count());
952 EXPECT_EQ(1, cache.disk_cache()->open_count());
953 EXPECT_EQ(1, cache.disk_cache()->create_count());
954
955 disk_cache::Entry* entry;
956 bool exists = cache.disk_cache()->OpenEntry(transaction.url, &entry);
957 EXPECT_FALSE(exists);
958}
959
960// Ensure that we don't cache requests served over bad HTTPS.
961TEST(HttpCache, SimpleGET_SSLError) {
962 MockHttpCache cache;
963
964 MockTransaction transaction = kSimpleGET_Transaction;
965 transaction.cert_status = net::CERT_STATUS_REVOKED;
966 ScopedMockTransaction scoped_transaction(transaction);
967
968 // write to the cache
969 RunTransactionTest(cache.http_cache(), transaction);
970
971 // Test that it was not cached.
972 transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
973
974 MockHttpRequest request(transaction);
975 TestCompletionCallback callback;
976
977 net::HttpTransaction* trans = cache.http_cache()->CreateTransaction();
978 ASSERT_TRUE(trans);
979
980 int rv = trans->Start(&request, &callback);
981 if (rv == net::ERR_IO_PENDING)
982 rv = callback.WaitForResult();
983 ASSERT_EQ(net::ERR_CACHE_MISS, rv);
984
985 trans->Destroy();
986}
license.botbf09a502008-08-24 00:55:55987