Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: net/http/http_cache_transaction.h

Issue 387017: Http Cache: Split HttpCache::Transaction to its own set... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_cache.cc ('k') | net/http/http_cache_transaction.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
rvargas (doing something else) 2009/11/11 02:02:47 Year already fixed.
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 // This file declares HttpCache::Transaction, a private class of HttpCache so
6 // it should only be included by http_cache.cc
7
8 #ifndef NET_HTTP_HTTP_CACHE_TRANSACTION_H_
9 #define NET_HTTP_HTTP_CACHE_TRANSACTION_H_
10
5 #include "net/http/http_cache.h" 11 #include "net/http/http_cache.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/compiler_specific.h"
11
12 #if defined(OS_POSIX)
13 #include <unistd.h>
14 #endif
15
16 #include "base/message_loop.h"
17 #include "base/pickle.h"
18 #include "base/ref_counted.h"
19 #include "base/string_util.h"
20 #include "base/time.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/load_flags.h"
23 #include "net/base/load_log.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/ssl_cert_request_info.h"
26 #include "net/disk_cache/disk_cache.h"
27 #include "net/http/http_network_layer.h"
28 #include "net/http/http_network_session.h"
29 #include "net/http/http_request_info.h"
30 #include "net/http/http_response_headers.h"
31 #include "net/http/http_response_info.h" 12 #include "net/http/http_response_info.h"
32 #include "net/http/http_transaction.h" 13 #include "net/http/http_transaction.h"
33 #include "net/http/http_util.h"
34 #include "net/http/partial_data.h"
35
36 using base::Time;
37 14
38 namespace net { 15 namespace net {
39 16
40 // disk cache entry data indices. 17 class HttpResponseHeaders;
41 enum { 18 class PartialData;
42 kResponseInfoIndex,
43 kResponseContentIndex
44 };
45 19
46 //----------------------------------------------------------------------------- 20 // This is the transaction that is returned by the HttpCache transaction
47 21 // factory.
48 struct HeaderNameAndValue {
49 const char* name;
50 const char* value;
51 };
52
53 // If the request includes one of these request headers, then avoid caching
54 // to avoid getting confused.
55 static const HeaderNameAndValue kPassThroughHeaders[] = {
56 { "if-unmodified-since", NULL }, // causes unexpected 412s
57 { "if-match", NULL }, // causes unexpected 412s
58 { "if-range", NULL },
59 { NULL, NULL }
60 };
61
62 struct ValidationHeaderInfo {
63 const char* request_header_name;
64 const char* related_response_header_name;
65 };
66
67 static const ValidationHeaderInfo kValidationHeaders[] = {
68 { "if-modified-since", "last-modified" },
69 { "if-none-match", "etag" },
70 };
71
72 // Helper struct to pair a header name with its value, for
73 // headers used to validate cache entries.
74 struct ValidationHeaders {
75 ValidationHeaders() : initialized(false) {}
76
77 std::string values[ARRAYSIZE_UNSAFE(kValidationHeaders)];
78 bool initialized;
79 };
80
81 // If the request includes one of these request headers, then avoid reusing
82 // our cached copy if any.
83 static const HeaderNameAndValue kForceFetchHeaders[] = {
84 { "cache-control", "no-cache" },
85 { "pragma", "no-cache" },
86 { NULL, NULL }
87 };
88
89 // If the request includes one of these request headers, then force our
90 // cached copy (if any) to be revalidated before reusing it.
91 static const HeaderNameAndValue kForceValidateHeaders[] = {
92 { "cache-control", "max-age=0" },
93 { NULL, NULL }
94 };
95
96 static bool HeaderMatches(const HttpUtil::HeadersIterator& h,
97 const HeaderNameAndValue* search) {
98 for (; search->name; ++search) {
99 if (!LowerCaseEqualsASCII(h.name_begin(), h.name_end(), search->name))
100 continue;
101
102 if (!search->value)
103 return true;
104
105 HttpUtil::ValuesIterator v(h.values_begin(), h.values_end(), ',');
106 while (v.GetNext()) {
107 if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value))
108 return true;
109 }
110 }
111 return false;
112 }
113
114 //-----------------------------------------------------------------------------
115
116 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* e)
117 : disk_entry(e),
118 writer(NULL),
119 will_process_pending_queue(false),
120 doomed(false) {
121 }
122
123 HttpCache::ActiveEntry::~ActiveEntry() {
124 if (disk_entry)
125 disk_entry->Close();
126 }
127
128 //-----------------------------------------------------------------------------
129
130 class HttpCache::Transaction : public HttpTransaction { 22 class HttpCache::Transaction : public HttpTransaction {
131 public: 23 public:
132 Transaction(HttpCache* cache, bool enable_range_support) 24 Transaction(HttpCache* cache, bool enable_range_support);
133 : request_(NULL),
134 cache_(cache->AsWeakPtr()),
135 entry_(NULL),
136 network_trans_(NULL),
137 callback_(NULL),
138 mode_(NONE),
139 reading_(false),
140 invalid_range_(false),
141 enable_range_support_(enable_range_support),
142 truncated_(false),
143 read_offset_(0),
144 effective_load_flags_(0),
145 final_upload_progress_(0),
146 ALLOW_THIS_IN_INITIALIZER_LIST(
147 network_info_callback_(this, &Transaction::OnNetworkInfoAvailable)),
148 ALLOW_THIS_IN_INITIALIZER_LIST(
149 network_read_callback_(this, &Transaction::OnNetworkReadCompleted)),
150 ALLOW_THIS_IN_INITIALIZER_LIST(
151 cache_read_callback_(new CancelableCompletionCallback<Transaction>(
152 this, &Transaction::OnCacheReadCompleted))),
153 ALLOW_THIS_IN_INITIALIZER_LIST(
154 cache_write_callback_(new CancelableCompletionCallback<Transaction>(
155 this, &Transaction::OnCacheWriteCompleted))),
156 ALLOW_THIS_IN_INITIALIZER_LIST(
157 entry_ready_callback_(new CancelableCompletionCallback<Transaction>(
158 this, &Transaction::OnCacheEntryReady))) {
159 }
160
161 // Clean up the transaction.
162 virtual ~Transaction(); 25 virtual ~Transaction();
163 26
164 // HttpTransaction methods: 27 // HttpTransaction methods:
165 virtual int Start(const HttpRequestInfo*, CompletionCallback*, LoadLog*); 28 virtual int Start(const HttpRequestInfo*, CompletionCallback*, LoadLog*);
166 virtual int RestartIgnoringLastError(CompletionCallback*); 29 virtual int RestartIgnoringLastError(CompletionCallback* callback);
167 virtual int RestartWithCertificate(X509Certificate* client_cert, 30 virtual int RestartWithCertificate(X509Certificate* client_cert,
168 CompletionCallback* callback); 31 CompletionCallback* callback);
169 virtual int RestartWithAuth(const std::wstring& username, 32 virtual int RestartWithAuth(const std::wstring& username,
170 const std::wstring& password, 33 const std::wstring& password,
171 CompletionCallback* callback); 34 CompletionCallback* callback);
172 virtual bool IsReadyToRestartForAuth(); 35 virtual bool IsReadyToRestartForAuth();
173 virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback*); 36 virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
174 virtual const HttpResponseInfo* GetResponseInfo() const; 37 virtual const HttpResponseInfo* GetResponseInfo() const;
175 virtual LoadState GetLoadState() const; 38 virtual LoadState GetLoadState() const;
176 virtual uint64 GetUploadProgress(void) const; 39 virtual uint64 GetUploadProgress(void) const;
177 40
178 // The transaction has the following modes, which apply to how it may access 41 // The transaction has the following modes, which apply to how it may access
179 // its cache entry. 42 // its cache entry.
180 // 43 //
181 // o If the mode of the transaction is NONE, then it is in "pass through" 44 // o If the mode of the transaction is NONE, then it is in "pass through"
182 // mode and all methods just forward to the inner network transaction. 45 // mode and all methods just forward to the inner network transaction.
183 // 46 //
(...skipping 30 matching lines...) Expand all
214 // Called by the HttpCache when the given disk cache entry becomes accessible 77 // Called by the HttpCache when the given disk cache entry becomes accessible
215 // to the transaction. Returns network error code. 78 // to the transaction. Returns network error code.
216 int EntryAvailable(ActiveEntry* entry); 79 int EntryAvailable(ActiveEntry* entry);
217 80
218 // This transaction is being deleted and we are not done writing to the cache. 81 // This transaction is being deleted and we are not done writing to the cache.
219 // We need to indicate that the response data was truncated. Returns true on 82 // We need to indicate that the response data was truncated. Returns true on
220 // success. 83 // success.
221 bool AddTruncatedFlag(); 84 bool AddTruncatedFlag();
222 85
223 private: 86 private:
87 static const size_t kNumValidationHeaders = 2;
eroman 2009/11/11 03:56:35 nit: i believe the struct declaration should prece
88 // Helper struct to pair a header name with its value, for
89 // headers used to validate cache entries.
90 struct ValidationHeaders {
91 ValidationHeaders() : initialized(false) {}
92
93 std::string values[kNumValidationHeaders];
94 bool initialized;
95 };
96
224 // This is a helper function used to trigger a completion callback. It may 97 // This is a helper function used to trigger a completion callback. It may
225 // only be called if callback_ is non-null. 98 // only be called if callback_ is non-null.
226 void DoCallback(int rv); 99 void DoCallback(int rv);
227 100
228 // This will trigger the completion callback if appropriate. 101 // This will trigger the completion callback if appropriate.
229 int HandleResult(int rv); 102 int HandleResult(int rv);
230 103
231 // Sets request_ and fields derived from it. 104 // Sets request_ and fields derived from it.
232 void SetRequest(LoadLog* load_log, const HttpRequestInfo* request); 105 void SetRequest(LoadLog* load_log, const HttpRequestInfo* request);
233 106
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 CompletionCallbackImpl<Transaction> network_info_callback_; 255 CompletionCallbackImpl<Transaction> network_info_callback_;
383 CompletionCallbackImpl<Transaction> network_read_callback_; 256 CompletionCallbackImpl<Transaction> network_read_callback_;
384 scoped_refptr<CancelableCompletionCallback<Transaction> > 257 scoped_refptr<CancelableCompletionCallback<Transaction> >
385 cache_read_callback_; 258 cache_read_callback_;
386 scoped_refptr<CancelableCompletionCallback<Transaction> > 259 scoped_refptr<CancelableCompletionCallback<Transaction> >
387 cache_write_callback_; 260 cache_write_callback_;
388 scoped_refptr<CancelableCompletionCallback<Transaction> > 261 scoped_refptr<CancelableCompletionCallback<Transaction> >
389 entry_ready_callback_; 262 entry_ready_callback_;
390 }; 263 };
391 264
392 HttpCache::Transaction::~Transaction() { 265 } // namespace net
393 if (cache_) {
394 if (entry_) {
395 bool cancel_request = reading_ && enable_range_support_;
396 if (cancel_request) {
397 if (partial_.get()) {
398 entry_->disk_entry->CancelSparseIO();
399 } else {
400 cancel_request &= (response_.headers->response_code() == 200);
401 }
402 }
403 266
404 cache_->DoneWithEntry(entry_, this, cancel_request); 267 #endif // NET_HTTP_HTTP_CACHE_TRANSACTION_H_
405 } else {
406 cache_->RemovePendingTransaction(this);
407 }
408 }
409
410 // If there is an outstanding callback, mark it as cancelled so running it
411 // does nothing.
412 cache_read_callback_->Cancel();
413 cache_write_callback_->Cancel();
414
415 // We could still have a cache read or write in progress, so we just null the
416 // cache_ pointer to signal that we are dead. See DoCacheReadCompleted.
417 cache_.reset();
418 }
419
420 int HttpCache::Transaction::Start(const HttpRequestInfo* request,
421 CompletionCallback* callback,
422 LoadLog* load_log) {
423 DCHECK(request);
424 DCHECK(callback);
425
426 // ensure that we only have one asynchronous call at a time.
427 DCHECK(!callback_);
428
429 if (!cache_)
430 return ERR_UNEXPECTED;
431
432 SetRequest(load_log, request);
433
434 int rv;
435
436 if (!ShouldPassThrough()) {
437 cache_key_ = cache_->GenerateCacheKey(request);
438
439 // requested cache access mode
440 if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
441 mode_ = READ;
442 } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
443 mode_ = WRITE;
444 } else {
445 mode_ = READ_WRITE;
446 }
447
448 // Downgrade to UPDATE if the request has been externally conditionalized.
449 if (external_validation_.initialized) {
450 if (mode_ & WRITE) {
451 // Strip off the READ_DATA bit (and maybe add back a READ_META bit
452 // in case READ was off).
453 mode_ = UPDATE;
454 } else {
455 mode_ = NONE;
456 }
457 }
458 }
459
460 // if must use cache, then we must fail. this can happen for back/forward
461 // navigations to a page generated via a form post.
462 if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE)
463 return ERR_CACHE_MISS;
464
465 if (mode_ == NONE) {
466 if (partial_.get())
467 partial_->RestoreHeaders(&custom_request_->extra_headers);
468 rv = BeginNetworkRequest();
469 } else {
470 rv = AddToEntry();
471 }
472
473 // setting this here allows us to check for the existance of a callback_ to
474 // determine if we are still inside Start.
475 if (rv == ERR_IO_PENDING)
476 callback_ = callback;
477
478 return rv;
479 }
480
481 int HttpCache::Transaction::RestartIgnoringLastError(
482 CompletionCallback* callback) {
483 DCHECK(callback);
484
485 // ensure that we only have one asynchronous call at a time.
486 DCHECK(!callback_);
487
488 if (!cache_)
489 return ERR_UNEXPECTED;
490
491 int rv = RestartNetworkRequest();
492
493 if (rv == ERR_IO_PENDING)
494 callback_ = callback;
495
496 return rv;
497 }
498
499 int HttpCache::Transaction::RestartWithCertificate(
500 X509Certificate* client_cert,
501 CompletionCallback* callback) {
502 DCHECK(callback);
503
504 // ensure that we only have one asynchronous call at a time.
505 DCHECK(!callback_);
506
507 if (!cache_)
508 return ERR_UNEXPECTED;
509
510 int rv = RestartNetworkRequestWithCertificate(client_cert);
511
512 if (rv == ERR_IO_PENDING)
513 callback_ = callback;
514
515 return rv;
516 }
517
518 int HttpCache::Transaction::RestartWithAuth(
519 const std::wstring& username,
520 const std::wstring& password,
521 CompletionCallback* callback) {
522 DCHECK(auth_response_.headers);
523 DCHECK(callback);
524
525 // Ensure that we only have one asynchronous call at a time.
526 DCHECK(!callback_);
527
528 if (!cache_)
529 return ERR_UNEXPECTED;
530
531 // Clear the intermediate response since we are going to start over.
532 auth_response_ = HttpResponseInfo();
533
534 int rv = RestartNetworkRequestWithAuth(username, password);
535
536 if (rv == ERR_IO_PENDING)
537 callback_ = callback;
538
539 return rv;
540 }
541
542 bool HttpCache::Transaction::IsReadyToRestartForAuth() {
543 if (!network_trans_.get())
544 return false;
545 return network_trans_->IsReadyToRestartForAuth();
546 }
547
548 int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
549 CompletionCallback* callback) {
550 DCHECK(buf);
551 DCHECK_GT(buf_len, 0);
552 DCHECK(callback);
553
554 DCHECK(!callback_);
555
556 if (!cache_)
557 return ERR_UNEXPECTED;
558
559 // If we have an intermediate auth response at this point, then it means the
560 // user wishes to read the network response (the error page). If there is a
561 // previous response in the cache then we should leave it intact.
562 if (auth_response_.headers && mode_ != NONE) {
563 DCHECK(mode_ & WRITE);
564 DoneWritingToEntry(mode_ == READ_WRITE);
565 mode_ = NONE;
566 }
567
568 reading_ = true;
569 int rv;
570
571 switch (mode_) {
572 case READ_WRITE:
573 DCHECK(partial_.get());
574 if (!network_trans_.get()) {
575 // We are just reading from the cache, but we may be writing later.
576 rv = ReadFromEntry(buf, buf_len);
577 break;
578 }
579 case NONE:
580 case WRITE:
581 DCHECK(network_trans_.get());
582 rv = ReadFromNetwork(buf, buf_len);
583 break;
584 case READ:
585 rv = ReadFromEntry(buf, buf_len);
586 break;
587 default:
588 NOTREACHED();
589 rv = ERR_FAILED;
590 }
591
592 if (rv == ERR_IO_PENDING) {
593 DCHECK(!callback_);
594 callback_ = callback;
595 }
596 return rv;
597 }
598
599 const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {
600 // Null headers means we encountered an error or haven't a response yet
601 if (auth_response_.headers)
602 return &auth_response_;
603 return (response_.headers || response_.ssl_info.cert ||
604 response_.cert_request_info) ? &response_ : NULL;
605 }
606
607 LoadState HttpCache::Transaction::GetLoadState() const {
608 if (network_trans_.get())
609 return network_trans_->GetLoadState();
610 if (entry_ || !request_)
611 return LOAD_STATE_IDLE;
612 return LOAD_STATE_WAITING_FOR_CACHE;
613 }
614
615 uint64 HttpCache::Transaction::GetUploadProgress() const {
616 if (network_trans_.get())
617 return network_trans_->GetUploadProgress();
618 return final_upload_progress_;
619 }
620
621 int HttpCache::Transaction::AddToEntry() {
622 ActiveEntry* entry = NULL;
623
624 if (!cache_)
625 return ERR_UNEXPECTED;
626
627 if (mode_ == WRITE) {
628 cache_->DoomEntry(cache_key_);
629 } else {
630 entry = cache_->FindActiveEntry(cache_key_);
631 if (!entry) {
632 LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
633 entry = cache_->OpenEntry(cache_key_);
634 LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
635 if (!entry) {
636 if (mode_ == READ_WRITE) {
637 mode_ = WRITE;
638 } else if (mode_ == UPDATE) {
639 // There is no cache entry to update; proceed without caching.
640 mode_ = NONE;
641 return BeginNetworkRequest();
642 } else {
643 if (cache_->mode() == PLAYBACK)
644 DLOG(INFO) << "Playback Cache Miss: " << request_->url;
645
646 // entry does not exist, and not permitted to create a new entry, so
647 // we must fail.
648 return HandleResult(ERR_CACHE_MISS);
649 }
650 }
651 }
652 }
653
654 if (mode_ == WRITE) {
655 DCHECK(!entry);
656 LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
657 entry = cache_->CreateEntry(cache_key_);
658 LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
659 if (!entry) {
660 DLOG(WARNING) << "unable to create cache entry";
661 mode_ = NONE;
662 if (partial_.get())
663 partial_->RestoreHeaders(&custom_request_->extra_headers);
664 return BeginNetworkRequest();
665 }
666 }
667
668
669 LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING);
670 return cache_->AddTransactionToEntry(entry, this);
671 }
672
673 int HttpCache::Transaction::EntryAvailable(ActiveEntry* entry) {
674 LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_WAITING);
675
676 // We now have access to the cache entry.
677 //
678 // o if we are the writer for the transaction, then we can start the network
679 // transaction.
680 //
681 // o if we are a reader for the transaction, then we can start reading the
682 // cache entry.
683 //
684 // o if we can read or write, then we should check if the cache entry needs
685 // to be validated and then issue a network request if needed or just read
686 // from the cache if the cache entry is already valid.
687 //
688 // o if we are set to UPDATE, then we are handling an externally
689 // conditionalized request (if-modified-since / if-none-match). We read
690 // the cache entry, and check if the request headers define a validation
691 // request.
692 //
693 int rv;
694 entry_ = entry;
695 switch (mode_) {
696 case READ:
697 rv = BeginCacheRead();
698 break;
699 case WRITE:
700 if (partial_.get())
701 partial_->RestoreHeaders(&custom_request_->extra_headers);
702 rv = BeginNetworkRequest();
703 break;
704 case READ_WRITE:
705 rv = BeginPartialCacheValidation();
706 break;
707 case UPDATE:
708 rv = BeginExternallyConditionalizedRequest();
709 break;
710 default:
711 NOTREACHED();
712 rv = ERR_FAILED;
713 }
714 return rv;
715 }
716
717 bool HttpCache::Transaction::AddTruncatedFlag() {
718 DCHECK(mode_ & WRITE);
719
720 // Don't set the flag for sparse entries.
721 if (partial_.get())
722 return true;
723
724 // Double check that there is something worth keeping.
725 if (!entry_->disk_entry->GetDataSize(kResponseContentIndex))
726 return false;
727
728 truncated_ = true;
729 WriteResponseInfoToEntry(true);
730 return true;
731 }
732
733 void HttpCache::Transaction::DoCallback(int rv) {
734 DCHECK(rv != ERR_IO_PENDING);
735 DCHECK(callback_);
736
737 // since Run may result in Read being called, clear callback_ up front.
738 CompletionCallback* c = callback_;
739 callback_ = NULL;
740 c->Run(rv);
741 }
742
743 int HttpCache::Transaction::HandleResult(int rv) {
744 DCHECK(rv != ERR_IO_PENDING);
745 if (callback_)
746 DoCallback(rv);
747 return rv;
748 }
749
750 void HttpCache::Transaction::SetRequest(LoadLog* load_log,
751 const HttpRequestInfo* request) {
752 load_log_ = load_log;
753 request_ = request;
754 effective_load_flags_ = request_->load_flags;
755
756 switch (cache_->mode()) {
757 case NORMAL:
758 break;
759 case RECORD:
760 // When in record mode, we want to NEVER load from the cache.
761 // The reason for this is beacuse we save the Set-Cookie headers
762 // (intentionally). If we read from the cache, we replay them
763 // prematurely.
764 effective_load_flags_ |= LOAD_BYPASS_CACHE;
765 break;
766 case PLAYBACK:
767 // When in playback mode, we want to load exclusively from the cache.
768 effective_load_flags_ |= LOAD_ONLY_FROM_CACHE;
769 break;
770 case DISABLE:
771 effective_load_flags_ |= LOAD_DISABLE_CACHE;
772 break;
773 }
774
775 // Some headers imply load flags. The order here is significant.
776 //
777 // LOAD_DISABLE_CACHE : no cache read or write
778 // LOAD_BYPASS_CACHE : no cache read
779 // LOAD_VALIDATE_CACHE : no cache read unless validation
780 //
781 // The former modes trump latter modes, so if we find a matching header we
782 // can stop iterating kSpecialHeaders.
783 //
784 static const struct {
785 const HeaderNameAndValue* search;
786 int load_flag;
787 } kSpecialHeaders[] = {
788 { kPassThroughHeaders, LOAD_DISABLE_CACHE },
789 { kForceFetchHeaders, LOAD_BYPASS_CACHE },
790 { kForceValidateHeaders, LOAD_VALIDATE_CACHE },
791 };
792
793 std::string new_extra_headers;
794 bool range_found = false;
795 bool external_validation_error = false;
796
797 // scan request headers to see if we have any that would impact our load flags
798 HttpUtil::HeadersIterator it(request_->extra_headers.begin(),
799 request_->extra_headers.end(),
800 "\r\n");
801 while (it.GetNext()) {
802 if (!LowerCaseEqualsASCII(it.name(), "range")) {
803 new_extra_headers.append(it.name_begin(), it.values_end());
804 new_extra_headers.append("\r\n");
805 } else {
806 if (enable_range_support_) {
807 range_found = true;
808 } else {
809 effective_load_flags_ |= LOAD_DISABLE_CACHE;
810 continue;
811 }
812 }
813 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) {
814 if (HeaderMatches(it, kSpecialHeaders[i].search)) {
815 effective_load_flags_ |= kSpecialHeaders[i].load_flag;
816 break;
817 }
818 }
819
820 // Check for conditionalization headers which may correspond with a
821 // cache validation request.
822 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); ++i) {
823 const ValidationHeaderInfo& info = kValidationHeaders[i];
824 if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(),
825 info.request_header_name)) {
826 if (!external_validation_.values[i].empty() || it.values().empty())
827 external_validation_error = true;
828 external_validation_.values[i] = it.values();
829 external_validation_.initialized = true;
830 break;
831 }
832 }
833 }
834
835 // We don't support ranges and validation headers.
836 if (range_found && external_validation_.initialized) {
837 LOG(WARNING) << "Byte ranges AND validation headers found.";
838 effective_load_flags_ |= LOAD_DISABLE_CACHE;
839 }
840
841 // If there is more than one validation header, we can't treat this request as
842 // a cache validation, since we don't know for sure which header the server
843 // will give us a response for (and they could be contradictory).
844 if (external_validation_error) {
845 LOG(WARNING) << "Multiple or malformed validation headers found.";
846 effective_load_flags_ |= LOAD_DISABLE_CACHE;
847 }
848
849 if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) {
850 partial_.reset(new PartialData);
851 if (partial_->Init(request_->extra_headers)) {
852 // We will be modifying the actual range requested to the server, so
853 // let's remove the header here.
854 custom_request_.reset(new HttpRequestInfo(*request_));
855 request_ = custom_request_.get();
856 custom_request_->extra_headers = new_extra_headers;
857 partial_->SetHeaders(new_extra_headers);
858 } else {
859 // The range is invalid or we cannot handle it properly.
860 LOG(WARNING) << "Invalid byte range found.";
861 effective_load_flags_ |= LOAD_DISABLE_CACHE;
862 partial_.reset(NULL);
863 }
864 }
865 }
866
867 bool HttpCache::Transaction::ShouldPassThrough() {
868 // We may have a null disk_cache if there is an error we cannot recover from,
869 // like not enough disk space, or sharing violations.
870 if (!cache_->disk_cache_.get())
871 return true;
872
873 // When using the record/playback modes, we always use the cache
874 // and we never pass through.
875 if (cache_->mode() == RECORD || cache_->mode() == PLAYBACK)
876 return false;
877
878 if (effective_load_flags_ & LOAD_DISABLE_CACHE)
879 return true;
880
881 if (request_->method == "GET")
882 return false;
883
884 if (request_->method == "POST" &&
885 request_->upload_data && request_->upload_data->identifier())
886 return false;
887
888 // TODO(darin): add support for caching HEAD responses
889 return true;
890 }
891
892 int HttpCache::Transaction::BeginCacheRead() {
893 DCHECK(mode_ == READ);
894
895 // Read response headers.
896 int rv = ReadResponseInfoFromEntry();
897 if (rv != OK)
898 return HandleResult(rv);
899
900 // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
901 if (response_.headers->response_code() == 206 || partial_.get()) {
902 NOTREACHED();
903 return HandleResult(ERR_CACHE_MISS);
904 }
905
906 // We don't have the whole resource.
907 if (truncated_)
908 return HandleResult(ERR_CACHE_MISS);
909
910 return HandleResult(rv);
911 }
912
913 int HttpCache::Transaction::BeginCacheValidation() {
914 DCHECK(mode_ == READ_WRITE);
915
916 if ((effective_load_flags_ & LOAD_PREFERRING_CACHE ||
917 !RequiresValidation()) && !partial_.get()) {
918 cache_->ConvertWriterToReader(entry_);
919 mode_ = READ;
920 } else {
921 // Make the network request conditional, to see if we may reuse our cached
922 // response. If we cannot do so, then we just resort to a normal fetch.
923 // Our mode remains READ_WRITE for a conditional request. We'll switch to
924 // either READ or WRITE mode once we hear back from the server.
925 if (!ConditionalizeRequest())
926 mode_ = WRITE;
927 return BeginNetworkRequest();
928 }
929 return HandleResult(OK);
930 }
931
932 int HttpCache::Transaction::BeginPartialCacheValidation() {
933 DCHECK(mode_ == READ_WRITE);
934
935 int rv = ReadResponseInfoFromEntry();
936 if (rv != OK) {
937 DCHECK(rv != ERR_IO_PENDING);
938 return HandleResult(rv);
939 }
940
941 if (response_.headers->response_code() != 206 && !partial_.get() &&
942 !truncated_)
943 return BeginCacheValidation();
944
945 if (!enable_range_support_)
946 return BeginCacheValidation();
947
948 bool byte_range_requested = partial_.get() != NULL;
949 if (byte_range_requested) {
950 if (OK != entry_->disk_entry->ReadyForSparseIO(entry_ready_callback_))
951 return ERR_IO_PENDING;
952 } else {
953 // The request is not for a range, but we have stored just ranges.
954 partial_.reset(new PartialData());
955 partial_->SetHeaders(request_->extra_headers);
956 if (!custom_request_.get()) {
957 custom_request_.reset(new HttpRequestInfo(*request_));
958 request_ = custom_request_.get();
959 }
960 }
961
962 return ValidateEntryHeadersAndContinue(byte_range_requested);
963 }
964
965 int HttpCache::Transaction::ValidateEntryHeadersAndContinue(
966 bool byte_range_requested) {
967 DCHECK(mode_ == READ_WRITE);
968
969 if (!cache_)
970 return HandleResult(ERR_UNEXPECTED);
971
972 if (!partial_->UpdateFromStoredHeaders(response_.headers, entry_->disk_entry,
973 truncated_)) {
974 // The stored data cannot be used. Get rid of it and restart this request.
975 // We need to also reset the |truncated_| flag as a new entry is created.
976 DoomPartialEntry(!byte_range_requested);
977 mode_ = WRITE;
978 truncated_ = false;
979 return AddToEntry();
980 }
981
982 if (!partial_->IsRequestedRangeOK()) {
983 // The stored data is fine, but the request may be invalid.
984 invalid_range_ = true;
985 }
986
987 return ContinuePartialCacheValidation();
988 }
989
990 int HttpCache::Transaction::ContinuePartialCacheValidation() {
991 DCHECK(mode_ == READ_WRITE);
992 int rv = partial_->PrepareCacheValidation(entry_->disk_entry,
993 &custom_request_->extra_headers);
994
995 if (!rv) {
996 // Don't invoke the callback before telling the cache we're done.
997 return rv;
998 }
999
1000 if (rv < 0) {
1001 DCHECK(rv != ERR_IO_PENDING);
1002 return HandleResult(rv);
1003 }
1004
1005 if (reading_ && partial_->IsCurrentRangeCached()) {
1006 rv = ReadFromEntry(read_buf_, read_buf_len_);
1007
1008 // We are supposed to hanlde errors here.
1009 if (rv < 0 && rv != ERR_IO_PENDING)
1010 HandleResult(rv);
1011 return rv;
1012 }
1013
1014 return BeginCacheValidation();
1015 }
1016
1017 int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
1018 DCHECK_EQ(UPDATE, mode_);
1019 DCHECK(external_validation_.initialized);
1020
1021 // Read the cached response.
1022 int rv = ReadResponseInfoFromEntry();
1023 if (rv != OK) {
1024 DCHECK(rv != ERR_IO_PENDING);
1025 return HandleResult(rv);
1026 }
1027
1028 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); i++) {
1029 if (external_validation_.values[i].empty())
1030 continue;
1031 // Retrieve either the cached response's "etag" or "last-modified" header.
1032 std::string validator;
1033 response_.headers->EnumerateHeader(
1034 NULL,
1035 kValidationHeaders[i].related_response_header_name,
1036 &validator);
1037
1038 if (response_.headers->response_code() != 200 || truncated_ ||
1039 validator.empty() || validator != external_validation_.values[i]) {
1040 // The externally conditionalized request is not a validation request
1041 // for our existing cache entry. Proceed with caching disabled.
1042 DoneWritingToEntry(true);
1043 }
1044 }
1045
1046 return BeginNetworkRequest();
1047 }
1048
1049 int HttpCache::Transaction::BeginNetworkRequest() {
1050 DCHECK(mode_ & WRITE || mode_ == NONE);
1051 DCHECK(!network_trans_.get());
1052
1053 // Create a network transaction.
1054 int rv = cache_->network_layer_->CreateTransaction(&network_trans_);
1055 if (rv != OK)
1056 return rv;
1057
1058 rv = network_trans_->Start(request_, &network_info_callback_, load_log_);
1059 if (rv != ERR_IO_PENDING)
1060 OnNetworkInfoAvailable(rv);
1061 return rv;
1062 }
1063
1064 int HttpCache::Transaction::RestartNetworkRequest() {
1065 DCHECK(mode_ & WRITE || mode_ == NONE);
1066 DCHECK(network_trans_.get());
1067
1068 int rv = network_trans_->RestartIgnoringLastError(&network_info_callback_);
1069 if (rv != ERR_IO_PENDING)
1070 OnNetworkInfoAvailable(rv);
1071 return rv;
1072 }
1073
1074 int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
1075 X509Certificate* client_cert) {
1076 DCHECK(mode_ & WRITE || mode_ == NONE);
1077 DCHECK(network_trans_.get());
1078
1079 int rv = network_trans_->RestartWithCertificate(client_cert,
1080 &network_info_callback_);
1081 if (rv != ERR_IO_PENDING)
1082 OnNetworkInfoAvailable(rv);
1083 return rv;
1084 }
1085
1086 int HttpCache::Transaction::RestartNetworkRequestWithAuth(
1087 const std::wstring& username,
1088 const std::wstring& password) {
1089 DCHECK(mode_ & WRITE || mode_ == NONE);
1090 DCHECK(network_trans_.get());
1091
1092 int rv = network_trans_->RestartWithAuth(username, password,
1093 &network_info_callback_);
1094 if (rv != ERR_IO_PENDING)
1095 OnNetworkInfoAvailable(rv);
1096 return rv;
1097 }
1098
1099 bool HttpCache::Transaction::RequiresValidation() {
1100 // TODO(darin): need to do more work here:
1101 // - make sure we have a matching request method
1102 // - watch out for cached responses that depend on authentication
1103 // In playback mode, nothing requires validation.
1104 if (cache_->mode() == net::HttpCache::PLAYBACK)
1105 return false;
1106
1107 if (effective_load_flags_ & LOAD_VALIDATE_CACHE)
1108 return true;
1109
1110 if (response_.headers->response_code() == 206 && !enable_range_support_)
1111 return true;
1112
1113 if (response_.headers->RequiresValidation(
1114 response_.request_time, response_.response_time, Time::Now()))
1115 return true;
1116
1117 // Since Vary header computation is fairly expensive, we save it for last.
1118 if (response_.vary_data.is_valid() &&
1119 !response_.vary_data.MatchesRequest(*request_, *response_.headers))
1120 return true;
1121
1122 return false;
1123 }
1124
1125 bool HttpCache::Transaction::ConditionalizeRequest() {
1126 DCHECK(response_.headers);
1127
1128 if (!enable_range_support_ && response_.headers->response_code() != 200) {
1129 // This only makes sense for cached 200 responses.
1130 return false;
1131 }
1132
1133 // This only makes sense for cached 200 or 206 responses.
1134 if (response_.headers->response_code() != 200 &&
1135 response_.headers->response_code() != 206)
1136 return false;
1137
1138 // Just use the first available ETag and/or Last-Modified header value.
1139 // TODO(darin): Or should we use the last?
1140
1141 std::string etag_value;
1142 response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
1143
1144 std::string last_modified_value;
1145 response_.headers->EnumerateHeader(NULL, "last-modified",
1146 &last_modified_value);
1147
1148 if (etag_value.empty() && last_modified_value.empty())
1149 return false;
1150
1151 if (!partial_.get()) {
1152 // Need to customize the request, so this forces us to allocate :(
1153 custom_request_.reset(new HttpRequestInfo(*request_));
1154 request_ = custom_request_.get();
1155 }
1156 DCHECK(custom_request_.get());
1157
1158 if (!etag_value.empty()) {
1159 if (partial_.get() && !partial_->IsCurrentRangeCached()) {
1160 // We don't want to switch to WRITE mode if we don't have this block of a
1161 // byte-range request because we may have other parts cached.
1162 custom_request_->extra_headers.append("If-Range: ");
1163 } else {
1164 custom_request_->extra_headers.append("If-None-Match: ");
1165 }
1166 custom_request_->extra_headers.append(etag_value);
1167 custom_request_->extra_headers.append("\r\n");
1168 if (partial_.get() && !partial_->IsCurrentRangeCached())
1169 return true;
1170 }
1171
1172 if (!last_modified_value.empty()) {
1173 if (partial_.get() && !partial_->IsCurrentRangeCached()) {
1174 custom_request_->extra_headers.append("If-Range: ");
1175 } else {
1176 custom_request_->extra_headers.append("If-Modified-Since: ");
1177 }
1178 custom_request_->extra_headers.append(last_modified_value);
1179 custom_request_->extra_headers.append("\r\n");
1180 }
1181
1182 return true;
1183 }
1184
1185 // We just received some headers from the server. We may have asked for a range,
1186 // in which case partial_ has an object. This could be the first network request
1187 // we make to fulfill the original request, or we may be already reading (from
1188 // the net and / or the cache). If we are not expecting a certain response, we
1189 // just bypass the cache for this request (but again, maybe we are reading), and
1190 // delete partial_ (so we are not able to "fix" the headers that we return to
1191 // the user). This results in either a weird response for the caller (we don't
1192 // expect it after all), or maybe a range that was not exactly what it was asked
1193 // for.
1194 //
1195 // For example, if the original request is for 30KB and we have the last 20KB,
1196 // we ask the server for the first 10KB. If the resourse has changed, we'll
1197 // end up forwarding the 200 back to the user (so far so good). However, if
1198 // we have instead the first 10KB, we end up sending back a byte range response
1199 // for the first 10KB, because we never asked the server for the last part. It's
1200 // just too complicated to restart the whole request from this point; and of
1201 // course, maybe we already returned the headers.
1202 bool HttpCache::Transaction::ValidatePartialResponse(
1203 const HttpResponseHeaders* headers) {
1204 int response_code = headers->response_code();
1205 bool partial_content = enable_range_support_ ? response_code == 206 : false;
1206
1207 if (!entry_)
1208 return false;
1209
1210 if (invalid_range_) {
1211 // We gave up trying to match this request with the stored data. If the
1212 // server is ok with the request, delete the entry, otherwise just ignore
1213 // this request
1214 if (partial_content || response_code == 200 || response_code == 304) {
1215 DoomPartialEntry(true);
1216 mode_ = NONE;
1217 } else {
1218 IgnoreRangeRequest();
1219 }
1220 return false;
1221 }
1222
1223 if (!partial_.get()) {
1224 // We are not expecting 206 but we may have one.
1225 if (partial_content)
1226 IgnoreRangeRequest();
1227
1228 return false;
1229 }
1230
1231 // TODO(rvargas): Do we need to consider other results here?.
1232 bool failure = response_code == 200 || response_code == 416;
1233
1234 if (partial_->IsCurrentRangeCached()) {
1235 // We asked for "If-None-Match: " so a 206 means a new object.
1236 if (partial_content)
1237 failure = true;
1238
1239 if (response_code == 304 && partial_->ResponseHeadersOK(headers))
1240 return false;
1241 } else {
1242 // We asked for "If-Range: " so a 206 means just another range.
1243 if (partial_content && partial_->ResponseHeadersOK(headers))
1244 return true;
1245
1246 // 304 is not expected here, but we'll spare the entry.
1247 }
1248
1249 if (failure) {
1250 // We cannot truncate this entry, it has to be deleted.
1251 DoomPartialEntry(true);
1252 mode_ = NONE;
1253 return false;
1254 }
1255
1256 IgnoreRangeRequest();
1257 return false;
1258 }
1259
1260 void HttpCache::Transaction::IgnoreRangeRequest() {
1261 // We have a problem. We may or may not be reading already (in which case we
1262 // returned the headers), but we'll just pretend that this request is not
1263 // using the cache and see what happens. Most likely this is the first
1264 // response from the server (it's not changing its mind midway, right?).
1265 if (mode_ & WRITE) {
1266 DoneWritingToEntry(mode_ != WRITE);
1267 } else if (mode_ & READ && entry_) {
1268 cache_->DoneReadingFromEntry(entry_, this);
1269 }
1270
1271 partial_.reset(NULL);
1272 entry_ = NULL;
1273 mode_ = NONE;
1274 }
1275
1276 int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) {
1277 int rv = network_trans_->Read(data, data_len, &network_read_callback_);
1278 read_buf_ = data;
1279 read_buf_len_ = data_len;
1280 if (rv >= 0)
1281 rv = DoNetworkReadCompleted(rv);
1282 return rv;
1283 }
1284
1285 int HttpCache::Transaction::ReadFromEntry(IOBuffer* data, int data_len) {
1286 DCHECK(entry_);
1287 int rv;
1288 cache_read_callback_->AddRef(); // Balanced in OnCacheReadCompleted.
1289 if (partial_.get()) {
1290 rv = partial_->CacheRead(entry_->disk_entry, data, data_len,
1291 cache_read_callback_);
1292 } else {
1293 rv = entry_->disk_entry->ReadData(kResponseContentIndex, read_offset_,
1294 data, data_len, cache_read_callback_);
1295 }
1296 read_buf_ = data;
1297 read_buf_len_ = data_len;
1298 if (rv != ERR_IO_PENDING)
1299 cache_read_callback_->Release();
1300
1301 if (rv >= 0)
1302 rv = DoCacheReadCompleted(rv);
1303
1304 return rv;
1305 }
1306
1307 int HttpCache::Transaction::ReadResponseInfoFromEntry() {
1308 DCHECK(entry_);
1309
1310 LoadLog::BeginEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_READ_INFO);
1311 bool read_ok =
1312 HttpCache::ReadResponseInfo(entry_->disk_entry, &response_, &truncated_);
1313 LoadLog::EndEvent(load_log_, LoadLog::TYPE_HTTP_CACHE_READ_INFO);
1314
1315 return read_ok ? OK : ERR_CACHE_READ_FAILURE;
1316 }
1317
1318 int HttpCache::Transaction::WriteToEntry(int index, int offset,
1319 IOBuffer* data, int data_len,
1320 CompletionCallback* callback) {
1321 if (!entry_)
1322 return data_len;
1323
1324 int rv = 0;
1325 if (!partial_.get() || !data_len) {
1326 rv = entry_->disk_entry->WriteData(index, offset, data, data_len, callback,
1327 true);
1328 } else {
1329 rv = partial_->CacheWrite(entry_->disk_entry, data, data_len, callback);
1330 }
1331
1332 if (rv != ERR_IO_PENDING && rv != data_len) {
1333 DLOG(ERROR) << "failed to write response data to cache";
1334 DoneWritingToEntry(false);
1335
1336 // We want to ignore errors writing to disk and just keep reading from
1337 // the network.
1338 rv = data_len;
1339 }
1340 return rv;
1341 }
1342
1343 void HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
1344 if (!entry_)
1345 return;
1346
1347 // Do not cache no-store content (unless we are record mode). Do not cache
1348 // content with cert errors either. This is to prevent not reporting net
1349 // errors when loading a resource from the cache. When we load a page over
1350 // HTTPS with a cert error we show an SSL blocking page. If the user clicks
1351 // proceed we reload the resource ignoring the errors. The loaded resource
1352 // is then cached. If that resource is subsequently loaded from the cache,
1353 // no net error is reported (even though the cert status contains the actual
1354 // errors) and no SSL blocking page is shown. An alternative would be to
1355 // reverse-map the cert status to a net error and replay the net error.
1356 if ((cache_->mode() != RECORD &&
1357 response_.headers->HasHeaderValue("cache-control", "no-store")) ||
1358 net::IsCertStatusError(response_.ssl_info.cert_status)) {
1359 DoneWritingToEntry(false);
1360 return;
1361 }
1362
1363 // When writing headers, we normally only write the non-transient
1364 // headers; when in record mode, record everything.
1365 bool skip_transient_headers = (cache_->mode() != RECORD);
1366
1367 if (truncated) {
1368 DCHECK_EQ(200, response_.headers->response_code());
1369 }
1370
1371 if (!HttpCache::WriteResponseInfo(entry_->disk_entry, &response_,
1372 skip_transient_headers, truncated)) {
1373 DLOG(ERROR) << "failed to write response info to cache";
1374 DoneWritingToEntry(false);
1375 }
1376 }
1377
1378 int HttpCache::Transaction::AppendResponseDataToEntry(
1379 IOBuffer* data, int data_len, CompletionCallback* callback) {
1380 if (!entry_ || !data_len)
1381 return data_len;
1382
1383 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
1384 return WriteToEntry(kResponseContentIndex, current_size, data, data_len,
1385 callback);
1386 }
1387
1388 void HttpCache::Transaction::TruncateResponseData() {
1389 if (!entry_)
1390 return;
1391
1392 // Truncate the stream.
1393 int rv = WriteToEntry(kResponseContentIndex, 0, NULL, 0, NULL);
1394 DCHECK(rv != ERR_IO_PENDING);
1395 }
1396
1397 void HttpCache::Transaction::DoneWritingToEntry(bool success) {
1398 if (!entry_)
1399 return;
1400
1401 if (cache_->mode() == RECORD)
1402 DLOG(INFO) << "Recorded: " << request_->method << request_->url
1403 << " status: " << response_.headers->response_code();
1404
1405 cache_->DoneWritingToEntry(entry_, success);
1406 entry_ = NULL;
1407 mode_ = NONE; // switch to 'pass through' mode
1408 }
1409
1410 void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
1411 cache_->DoneWithEntry(entry_, this, false);
1412 cache_->DoomEntry(cache_key_);
1413 entry_ = NULL;
1414 if (delete_object)
1415 partial_.reset(NULL);
1416 }
1417
1418 int HttpCache::Transaction::DoNetworkReadCompleted(int result) {
1419 DCHECK(mode_ & WRITE || mode_ == NONE);
1420
1421 if (!cache_)
1422 return HandleResult(ERR_UNEXPECTED);
1423
1424 cache_write_callback_->AddRef(); // Balanced in DoCacheWriteCompleted.
1425
1426 result = AppendResponseDataToEntry(read_buf_, result, cache_write_callback_);
1427 if (result == ERR_IO_PENDING)
1428 return result;
1429
1430 return DoCacheWriteCompleted(result);
1431 }
1432
1433 int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
1434 partial_->OnNetworkReadCompleted(result);
1435
1436 if (result == 0) { // End of file.
1437 if (mode_ == READ_WRITE) {
1438 // We need to move on to the next range.
1439 network_trans_.reset();
1440 result = ContinuePartialCacheValidation();
1441 if (result != OK)
1442 // Any error was already handled.
1443 return result;
1444 }
1445 DoneWritingToEntry(true);
1446 }
1447 return HandleResult(result);
1448 }
1449
1450 int HttpCache::Transaction::DoCacheReadCompleted(int result) {
1451 DCHECK(cache_);
1452
1453 if (!cache_)
1454 return HandleResult(ERR_UNEXPECTED);
1455
1456 if (partial_.get())
1457 return DoPartialCacheReadCompleted(result);
1458
1459 if (result > 0) {
1460 read_offset_ += result;
1461 } else if (result == 0) { // End of file.
1462 cache_->DoneReadingFromEntry(entry_, this);
1463 entry_ = NULL;
1464 }
1465 return HandleResult(result);
1466 }
1467
1468 int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
1469 partial_->OnCacheReadCompleted(result);
1470
1471 if (result == 0) { // End of file.
1472 if (partial_.get() && mode_ == READ_WRITE) {
1473 // We need to move on to the next range.
1474 result = ContinuePartialCacheValidation();
1475 if (result != OK)
1476 // Any error was already handled.
1477 return result;
1478 cache_->ConvertWriterToReader(entry_);
1479 }
1480 cache_->DoneReadingFromEntry(entry_, this);
1481 entry_ = NULL;
1482 }
1483 return HandleResult(result);
1484 }
1485
1486 int HttpCache::Transaction::DoCacheWriteCompleted(int result) {
1487 DCHECK(cache_);
1488 // Balance the AddRef from DoNetworkReadCompleted.
1489 cache_write_callback_->Release();
1490 if (!cache_)
1491 return HandleResult(ERR_UNEXPECTED);
1492
1493 if (result < 0)
1494 return HandleResult(result);
1495
1496 if (partial_.get())
1497 return DoPartialNetworkReadCompleted(result);
1498
1499 if (result == 0) // End of file.
1500 DoneWritingToEntry(true);
1501
1502 return HandleResult(result);
1503 }
1504
1505 void HttpCache::Transaction::OnNetworkInfoAvailable(int result) {
1506 DCHECK(result != ERR_IO_PENDING);
1507
1508 if (!cache_) {
1509 HandleResult(ERR_UNEXPECTED);
1510 return;
1511 }
1512
1513 if (result == OK) {
1514 const HttpResponseInfo* new_response = network_trans_->GetResponseInfo();
1515 if (new_response->headers->response_code() == 401 ||
1516 new_response->headers->response_code() == 407) {
1517 auth_response_ = *new_response;
1518 } else {
1519 bool partial_content = ValidatePartialResponse(new_response->headers);
1520 if (partial_content && mode_ == READ_WRITE && !truncated_ &&
1521 response_.headers->response_code() == 200) {
1522 // We have stored the full entry, but it changed and the server is
1523 // sending a range. We have to delete the old entry.
1524 DoneWritingToEntry(false);
1525 }
1526
1527 // Are we expecting a response to a conditional query?
1528 if (mode_ == READ_WRITE || mode_ == UPDATE) {
1529 if (new_response->headers->response_code() == 304 || partial_content) {
1530 // Update cached response based on headers in new_response.
1531 // TODO(wtc): should we update cached certificate
1532 // (response_.ssl_info), too?
1533 response_.headers->Update(*new_response->headers);
1534 response_.response_time = new_response->response_time;
1535 response_.request_time = new_response->request_time;
1536
1537 if (response_.headers->HasHeaderValue("cache-control", "no-store")) {
1538 cache_->DoomEntry(cache_key_);
1539 } else {
1540 // If we are already reading, we already updated the headers for
1541 // this request; doing it again will change Content-Length.
1542 if (!reading_)
1543 WriteResponseInfoToEntry(false);
1544 }
1545
1546 if (mode_ == UPDATE) {
1547 DCHECK(!partial_content);
1548 // We got a "not modified" response and already updated the
1549 // corresponding cache entry above.
1550 //
1551 // By closing the cached entry now, we make sure that the
1552 // 304 rather than the cached 200 response, is what will be
1553 // returned to the user.
1554 DoneWritingToEntry(true);
1555 } else if (entry_ && !partial_content) {
1556 DCHECK_EQ(READ_WRITE, mode_);
1557 if (!partial_.get() || partial_->IsLastRange()) {
1558 cache_->ConvertWriterToReader(entry_);
1559 mode_ = READ;
1560 }
1561 // We no longer need the network transaction, so destroy it.
1562 final_upload_progress_ = network_trans_->GetUploadProgress();
1563 network_trans_.reset();
1564 }
1565 } else {
1566 mode_ = WRITE;
1567 }
1568 }
1569
1570 if (!(mode_ & READ)) {
1571 // We change the value of Content-Length for partial content.
1572 if (partial_content && partial_.get())
1573 partial_->FixContentLength(new_response->headers);
1574
1575 response_ = *new_response;
1576 WriteResponseInfoToEntry(truncated_);
1577
1578 // Truncate response data.
1579 TruncateResponseData();
1580
1581 // If this response is a redirect, then we can stop writing now. (We
1582 // don't need to cache the response body of a redirect.)
1583 if (response_.headers->IsRedirect(NULL))
1584 DoneWritingToEntry(true);
1585 }
1586 if (reading_ && partial_.get()) {
1587 if (network_trans_.get()) {
1588 result = ReadFromNetwork(read_buf_, read_buf_len_);
1589 } else {
1590 result = ReadFromEntry(read_buf_, read_buf_len_);
1591 }
1592 if (result >= 0 || result == net::ERR_IO_PENDING)
1593 return;
1594 } else if (mode_ != NONE && partial_.get()) {
1595 // We are about to return the headers for a byte-range request to the
1596 // user, so let's fix them.
1597 partial_->FixResponseHeaders(response_.headers);
1598 }
1599 }
1600 } else if (IsCertificateError(result)) {
1601 const HttpResponseInfo* response = network_trans_->GetResponseInfo();
1602 // If we get a certificate error, then there is a certificate in ssl_info,
1603 // so GetResponseInfo() should never returns NULL here.
1604 DCHECK(response);
1605 response_.ssl_info = response->ssl_info;
1606 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
1607 const HttpResponseInfo* response = network_trans_->GetResponseInfo();
1608 DCHECK(response);
1609 response_.cert_request_info = response->cert_request_info;
1610 }
1611 HandleResult(result);
1612 }
1613
1614 void HttpCache::Transaction::OnNetworkReadCompleted(int result) {
1615 DoNetworkReadCompleted(result);
1616 }
1617
1618 void HttpCache::Transaction::OnCacheReadCompleted(int result) {
1619 cache_read_callback_->Release(); // Balance the AddRef from ReadFromEntry.
1620 DoCacheReadCompleted(result);
1621 }
1622
1623 void HttpCache::Transaction::OnCacheWriteCompleted(int result) {
1624 DoCacheWriteCompleted(result);
1625 }
1626
1627 void HttpCache::Transaction::OnCacheEntryReady(int result) {
1628 DCHECK_EQ(OK, result);
1629 ValidateEntryHeadersAndContinue(true);
1630 }
1631
1632 //-----------------------------------------------------------------------------
1633
1634 HttpCache::HttpCache(HostResolver* host_resolver,
1635 ProxyService* proxy_service,
1636 SSLConfigService* ssl_config_service,
1637 const FilePath& cache_dir,
1638 int cache_size)
1639 : disk_cache_dir_(cache_dir),
1640 mode_(NORMAL),
1641 type_(DISK_CACHE),
1642 network_layer_(HttpNetworkLayer::CreateFactory(
1643 host_resolver, proxy_service, ssl_config_service)),
1644 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1645 enable_range_support_(true),
1646 cache_size_(cache_size) {
1647 }
1648
1649 HttpCache::HttpCache(HttpNetworkSession* session,
1650 const FilePath& cache_dir,
1651 int cache_size)
1652 : disk_cache_dir_(cache_dir),
1653 mode_(NORMAL),
1654 type_(DISK_CACHE),
1655 network_layer_(HttpNetworkLayer::CreateFactory(session)),
1656 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1657 enable_range_support_(true),
1658 cache_size_(cache_size) {
1659 }
1660
1661 HttpCache::HttpCache(HostResolver* host_resolver,
1662 ProxyService* proxy_service,
1663 SSLConfigService* ssl_config_service,
1664 int cache_size)
1665 : mode_(NORMAL),
1666 type_(MEMORY_CACHE),
1667 network_layer_(HttpNetworkLayer::CreateFactory(
1668 host_resolver, proxy_service, ssl_config_service)),
1669 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1670 enable_range_support_(true),
1671 cache_size_(cache_size) {
1672 }
1673
1674 HttpCache::HttpCache(HttpTransactionFactory* network_layer,
1675 disk_cache::Backend* disk_cache)
1676 : mode_(NORMAL),
1677 type_(DISK_CACHE),
1678 network_layer_(network_layer),
1679 disk_cache_(disk_cache),
1680 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
1681 enable_range_support_(true),
1682 cache_size_(0) {
1683 }
1684
1685 HttpCache::~HttpCache() {
1686 // If we have any active entries remaining, then we need to deactivate them.
1687 // We may have some pending calls to OnProcessPendingQueue, but since those
1688 // won't run (due to our destruction), we can simply ignore the corresponding
1689 // will_process_pending_queue flag.
1690 while (!active_entries_.empty()) {
1691 ActiveEntry* entry = active_entries_.begin()->second;
1692 entry->will_process_pending_queue = false;
1693 entry->pending_queue.clear();
1694 entry->readers.clear();
1695 entry->writer = NULL;
1696 DeactivateEntry(entry);
1697 }
1698
1699 ActiveEntriesSet::iterator it = doomed_entries_.begin();
1700 for (; it != doomed_entries_.end(); ++it)
1701 delete *it;
1702 }
1703
1704 disk_cache::Backend* HttpCache::GetBackend() {
1705 if (disk_cache_.get())
1706 return disk_cache_.get();
1707
1708 DCHECK_GE(cache_size_, 0);
1709 if (type_ == MEMORY_CACHE) {
1710 // We may end up with no folder name and no cache if the initialization
1711 // of the disk cache fails. We want to be sure that what we wanted to have
1712 // was an in-memory cache.
1713 disk_cache_.reset(disk_cache::CreateInMemoryCacheBackend(cache_size_));
1714 } else if (!disk_cache_dir_.empty()) {
1715 disk_cache_.reset(disk_cache::CreateCacheBackend(disk_cache_dir_, true,
1716 cache_size_, type_));
1717 disk_cache_dir_ = FilePath(); // Reclaim memory.
1718 }
1719 return disk_cache_.get();
1720 }
1721
1722 int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
1723 // Do lazy initialization of disk cache if needed.
1724 GetBackend();
1725 trans->reset(new HttpCache::Transaction(this, enable_range_support_));
1726 return OK;
1727 }
1728
1729 HttpCache* HttpCache::GetCache() {
1730 return this;
1731 }
1732
1733 HttpNetworkSession* HttpCache::GetSession() {
1734 net::HttpNetworkLayer* network =
1735 static_cast<net::HttpNetworkLayer*>(network_layer_.get());
1736 return network->GetSession();
1737 }
1738
1739 void HttpCache::Suspend(bool suspend) {
1740 network_layer_->Suspend(suspend);
1741 }
1742
1743 // static
1744 bool HttpCache::ParseResponseInfo(const char* data, int len,
1745 HttpResponseInfo* response_info,
1746 bool* response_truncated) {
1747 Pickle pickle(data, len);
1748 return response_info->InitFromPickle(pickle, response_truncated);
1749 }
1750
1751 // static
1752 bool HttpCache::ReadResponseInfo(disk_cache::Entry* disk_entry,
1753 HttpResponseInfo* response_info,
1754 bool* response_truncated) {
1755 int size = disk_entry->GetDataSize(kResponseInfoIndex);
1756
1757 scoped_refptr<IOBuffer> buffer = new IOBuffer(size);
1758 int rv = disk_entry->ReadData(kResponseInfoIndex, 0, buffer, size, NULL);
1759 if (rv != size) {
1760 DLOG(ERROR) << "ReadData failed: " << rv;
1761 return false;
1762 }
1763
1764 return ParseResponseInfo(buffer->data(), size, response_info,
1765 response_truncated);
1766 }
1767
1768 // static
1769 bool HttpCache::WriteResponseInfo(disk_cache::Entry* disk_entry,
1770 const HttpResponseInfo* response_info,
1771 bool skip_transient_headers,
1772 bool response_truncated) {
1773 Pickle pickle;
1774 response_info->Persist(
1775 &pickle, skip_transient_headers, response_truncated);
1776
1777 scoped_refptr<WrappedIOBuffer> data = new WrappedIOBuffer(
1778 reinterpret_cast<const char*>(pickle.data()));
1779 int len = static_cast<int>(pickle.size());
1780
1781 return disk_entry->WriteData(kResponseInfoIndex, 0, data, len, NULL,
1782 true) == len;
1783 }
1784
1785 // Generate a key that can be used inside the cache.
1786 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
1787 // Strip out the reference, username, and password sections of the URL.
1788 std::string url = HttpUtil::SpecForRequest(request->url);
1789
1790 DCHECK(mode_ != DISABLE);
1791 if (mode_ == NORMAL) {
1792 // No valid URL can begin with numerals, so we should not have to worry
1793 // about collisions with normal URLs.
1794 if (request->upload_data && request->upload_data->identifier())
1795 url.insert(0, StringPrintf("%lld/", request->upload_data->identifier()));
1796 return url;
1797 }
1798
1799 // In playback and record mode, we cache everything.
1800
1801 // Lazily initialize.
1802 if (playback_cache_map_ == NULL)
1803 playback_cache_map_.reset(new PlaybackCacheMap());
1804
1805 // Each time we request an item from the cache, we tag it with a
1806 // generation number. During playback, multiple fetches for the same
1807 // item will use the same generation number and pull the proper
1808 // instance of an URL from the cache.
1809 int generation = 0;
1810 DCHECK(playback_cache_map_ != NULL);
1811 if (playback_cache_map_->find(url) != playback_cache_map_->end())
1812 generation = (*playback_cache_map_)[url];
1813 (*playback_cache_map_)[url] = generation + 1;
1814
1815 // The key into the cache is GENERATION # + METHOD + URL.
1816 std::string result = IntToString(generation);
1817 result.append(request->method);
1818 result.append(url);
1819 return result;
1820 }
1821
1822 void HttpCache::DoomEntry(const std::string& key) {
1823 // Need to abandon the ActiveEntry, but any transaction attached to the entry
1824 // should not be impacted. Dooming an entry only means that it will no
1825 // longer be returned by FindActiveEntry (and it will also be destroyed once
1826 // all consumers are finished with the entry).
1827 ActiveEntriesMap::iterator it = active_entries_.find(key);
1828 if (it == active_entries_.end()) {
1829 disk_cache_->DoomEntry(key);
1830 } else {
1831 ActiveEntry* entry = it->second;
1832 active_entries_.erase(it);
1833
1834 // We keep track of doomed entries so that we can ensure that they are
1835 // cleaned up properly when the cache is destroyed.
1836 doomed_entries_.insert(entry);
1837
1838 entry->disk_entry->Doom();
1839 entry->doomed = true;
1840
1841 DCHECK(entry->writer || !entry->readers.empty());
1842 }
1843 }
1844
1845 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) {
1846 DCHECK(entry->doomed);
1847 DCHECK(!entry->writer);
1848 DCHECK(entry->readers.empty());
1849 DCHECK(entry->pending_queue.empty());
1850
1851 ActiveEntriesSet::iterator it = doomed_entries_.find(entry);
1852 DCHECK(it != doomed_entries_.end());
1853 doomed_entries_.erase(it);
1854
1855 delete entry;
1856 }
1857
1858 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) {
1859 ActiveEntriesMap::const_iterator it = active_entries_.find(key);
1860 return it != active_entries_.end() ? it->second : NULL;
1861 }
1862
1863 HttpCache::ActiveEntry* HttpCache::OpenEntry(const std::string& key) {
1864 DCHECK(!FindActiveEntry(key));
1865
1866 disk_cache::Entry* disk_entry;
1867 if (!disk_cache_->OpenEntry(key, &disk_entry))
1868 return NULL;
1869
1870 return ActivateEntry(key, disk_entry);
1871 }
1872
1873 HttpCache::ActiveEntry* HttpCache::CreateEntry(const std::string& key) {
1874 DCHECK(!FindActiveEntry(key));
1875
1876 disk_cache::Entry* disk_entry;
1877 if (!disk_cache_->CreateEntry(key, &disk_entry))
1878 return NULL;
1879
1880 return ActivateEntry(key, disk_entry);
1881 }
1882
1883 void HttpCache::DestroyEntry(ActiveEntry* entry) {
1884 if (entry->doomed) {
1885 FinalizeDoomedEntry(entry);
1886 } else {
1887 DeactivateEntry(entry);
1888 }
1889 }
1890
1891 HttpCache::ActiveEntry* HttpCache::ActivateEntry(
1892 const std::string& key,
1893 disk_cache::Entry* disk_entry) {
1894 ActiveEntry* entry = new ActiveEntry(disk_entry);
1895 active_entries_[key] = entry;
1896 return entry;
1897 }
1898
1899 void HttpCache::DeactivateEntry(ActiveEntry* entry) {
1900 DCHECK(!entry->will_process_pending_queue);
1901 DCHECK(!entry->doomed);
1902 DCHECK(!entry->writer);
1903 DCHECK(entry->readers.empty());
1904 DCHECK(entry->pending_queue.empty());
1905
1906 std::string key = entry->disk_entry->GetKey();
1907 if (key.empty())
1908 return SlowDeactivateEntry(entry);
1909
1910 ActiveEntriesMap::iterator it = active_entries_.find(key);
1911 DCHECK(it != active_entries_.end());
1912 DCHECK(it->second == entry);
1913
1914 active_entries_.erase(it);
1915 delete entry;
1916 }
1917
1918 // We don't know this entry's key so we have to find it without it.
1919 void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) {
1920 for (ActiveEntriesMap::iterator it = active_entries_.begin();
1921 it != active_entries_.end(); ++it) {
1922 if (it->second == entry) {
1923 active_entries_.erase(it);
1924 delete entry;
1925 break;
1926 }
1927 }
1928 }
1929
1930 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) {
1931 DCHECK(entry);
1932
1933 // We implement a basic reader/writer lock for the disk cache entry. If
1934 // there is already a writer, then everyone has to wait for the writer to
1935 // finish before they can access the cache entry. There can be multiple
1936 // readers.
1937 //
1938 // NOTE: If the transaction can only write, then the entry should not be in
1939 // use (since any existing entry should have already been doomed).
1940
1941 if (entry->writer || entry->will_process_pending_queue) {
1942 entry->pending_queue.push_back(trans);
1943 return ERR_IO_PENDING;
1944 }
1945
1946 if (trans->mode() & Transaction::WRITE) {
1947 // transaction needs exclusive access to the entry
1948 if (entry->readers.empty()) {
1949 entry->writer = trans;
1950 } else {
1951 entry->pending_queue.push_back(trans);
1952 return ERR_IO_PENDING;
1953 }
1954 } else {
1955 // transaction needs read access to the entry
1956 entry->readers.push_back(trans);
1957 }
1958
1959 // We do this before calling EntryAvailable to force any further calls to
1960 // AddTransactionToEntry to add their transaction to the pending queue, which
1961 // ensures FIFO ordering.
1962 if (!entry->writer && !entry->pending_queue.empty())
1963 ProcessPendingQueue(entry);
1964
1965 return trans->EntryAvailable(entry);
1966 }
1967
1968 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans,
1969 bool cancel) {
1970 // If we already posted a task to move on to the next transaction and this was
1971 // the writer, there is nothing to cancel.
1972 if (entry->will_process_pending_queue && entry->readers.empty())
1973 return;
1974
1975 if (entry->writer) {
1976 DCHECK(trans == entry->writer);
1977
1978 // Assume there was a failure.
1979 bool success = false;
1980 if (cancel) {
1981 DCHECK(entry->disk_entry);
1982 // This is a successful operation in the sense that we want to keep the
1983 // entry.
1984 success = trans->AddTruncatedFlag();
1985 }
1986 DoneWritingToEntry(entry, success);
1987 } else {
1988 DoneReadingFromEntry(entry, trans);
1989 }
1990 }
1991
1992 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) {
1993 DCHECK(entry->readers.empty());
1994
1995 entry->writer = NULL;
1996
1997 if (success) {
1998 ProcessPendingQueue(entry);
1999 } else {
2000 DCHECK(!entry->will_process_pending_queue);
2001
2002 // We failed to create this entry.
2003 TransactionList pending_queue;
2004 pending_queue.swap(entry->pending_queue);
2005
2006 entry->disk_entry->Doom();
2007 DestroyEntry(entry);
2008
2009 // We need to do something about these pending entries, which now need to
2010 // be added to a new entry.
2011 while (!pending_queue.empty()) {
2012 pending_queue.front()->AddToEntry();
2013 pending_queue.pop_front();
2014 }
2015 }
2016 }
2017
2018 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) {
2019 DCHECK(!entry->writer);
2020
2021 TransactionList::iterator it =
2022 std::find(entry->readers.begin(), entry->readers.end(), trans);
2023 DCHECK(it != entry->readers.end());
2024
2025 entry->readers.erase(it);
2026
2027 ProcessPendingQueue(entry);
2028 }
2029
2030 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) {
2031 DCHECK(entry->writer);
2032 DCHECK(entry->writer->mode() == Transaction::READ_WRITE);
2033 DCHECK(entry->readers.empty());
2034
2035 Transaction* trans = entry->writer;
2036
2037 entry->writer = NULL;
2038 entry->readers.push_back(trans);
2039
2040 ProcessPendingQueue(entry);
2041 }
2042
2043 void HttpCache::RemovePendingTransaction(Transaction* trans) {
2044 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key());
2045 bool found = false;
2046 if (i != active_entries_.end())
2047 found = RemovePendingTransactionFromEntry(i->second, trans);
2048
2049 if (found)
2050 return;
2051
2052 ActiveEntriesSet::iterator it = doomed_entries_.begin();
2053 for (; it != doomed_entries_.end() && !found; ++it)
2054 found = RemovePendingTransactionFromEntry(*it, trans);
2055 }
2056
2057 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry,
2058 Transaction* trans) {
2059 TransactionList& pending_queue = entry->pending_queue;
2060
2061 TransactionList::iterator j =
2062 find(pending_queue.begin(), pending_queue.end(), trans);
2063 if (j == pending_queue.end())
2064 return false;
2065
2066 pending_queue.erase(j);
2067 return true;
2068 }
2069
2070 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) {
2071 // Multiple readers may finish with an entry at once, so we want to batch up
2072 // calls to OnProcessPendingQueue. This flag also tells us that we should
2073 // not delete the entry before OnProcessPendingQueue runs.
2074 if (entry->will_process_pending_queue)
2075 return;
2076 entry->will_process_pending_queue = true;
2077
2078 MessageLoop::current()->PostTask(FROM_HERE,
2079 task_factory_.NewRunnableMethod(&HttpCache::OnProcessPendingQueue,
2080 entry));
2081 }
2082
2083 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) {
2084 entry->will_process_pending_queue = false;
2085 DCHECK(!entry->writer);
2086
2087 // If no one is interested in this entry, then we can de-activate it.
2088 if (entry->pending_queue.empty()) {
2089 if (entry->readers.empty())
2090 DestroyEntry(entry);
2091 return;
2092 }
2093
2094 // Promote next transaction from the pending queue.
2095 Transaction* next = entry->pending_queue.front();
2096 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty())
2097 return; // Have to wait.
2098
2099 entry->pending_queue.erase(entry->pending_queue.begin());
2100
2101 AddTransactionToEntry(entry, next);
2102 }
2103
2104 void HttpCache::CloseIdleConnections() {
2105 net::HttpNetworkLayer* network =
2106 static_cast<net::HttpNetworkLayer*>(network_layer_.get());
2107 HttpNetworkSession* session = network->GetSession();
2108 if (session) {
2109 session->tcp_socket_pool()->CloseIdleSockets();
2110 }
2111 }
2112
2113 //-----------------------------------------------------------------------------
2114
2115 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_cache.cc ('k') | net/http/http_cache_transaction.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698