• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include "net/http/http_cache_transaction.h"
6 
7 #include "build/build_config.h"
8 
9 #if defined(OS_POSIX)
10 #include <unistd.h>
11 #endif
12 
13 #include <string>
14 
15 #include "base/compiler_specific.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/metrics/field_trial.h"
18 #include "base/metrics/histogram.h"
19 #include "base/string_util.h"
20 #include "base/time.h"
21 #include "net/base/cert_status_flags.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/load_flags.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/net_log.h"
26 #include "net/base/network_delegate.h"
27 #include "net/base/ssl_cert_request_info.h"
28 #include "net/base/ssl_config_service.h"
29 #include "net/disk_cache/disk_cache.h"
30 #include "net/http/disk_cache_based_ssl_host_info.h"
31 #include "net/http/http_network_session.h"
32 #include "net/http/http_request_info.h"
33 #include "net/http/http_response_headers.h"
34 #include "net/http/http_transaction.h"
35 #include "net/http/http_util.h"
36 #include "net/http/partial_data.h"
37 
38 using base::Time;
39 
40 namespace net {
41 
42 struct HeaderNameAndValue {
43   const char* name;
44   const char* value;
45 };
46 
47 // If the request includes one of these request headers, then avoid caching
48 // to avoid getting confused.
49 static const HeaderNameAndValue kPassThroughHeaders[] = {
50   { "if-unmodified-since", NULL },  // causes unexpected 412s
51   { "if-match", NULL },             // causes unexpected 412s
52   { "if-range", NULL },
53   { NULL, NULL }
54 };
55 
56 struct ValidationHeaderInfo {
57   const char* request_header_name;
58   const char* related_response_header_name;
59 };
60 
61 static const ValidationHeaderInfo kValidationHeaders[] = {
62   { "if-modified-since", "last-modified" },
63   { "if-none-match", "etag" },
64 };
65 
66 // If the request includes one of these request headers, then avoid reusing
67 // our cached copy if any.
68 static const HeaderNameAndValue kForceFetchHeaders[] = {
69   { "cache-control", "no-cache" },
70   { "pragma", "no-cache" },
71   { NULL, NULL }
72 };
73 
74 // If the request includes one of these request headers, then force our
75 // cached copy (if any) to be revalidated before reusing it.
76 static const HeaderNameAndValue kForceValidateHeaders[] = {
77   { "cache-control", "max-age=0" },
78   { NULL, NULL }
79 };
80 
HeaderMatches(const HttpRequestHeaders & headers,const HeaderNameAndValue * search)81 static bool HeaderMatches(const HttpRequestHeaders& headers,
82                           const HeaderNameAndValue* search) {
83   for (; search->name; ++search) {
84     std::string header_value;
85     if (!headers.GetHeader(search->name, &header_value))
86       continue;
87 
88     if (!search->value)
89       return true;
90 
91     HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ',');
92     while (v.GetNext()) {
93       if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value))
94         return true;
95     }
96   }
97   return false;
98 }
99 
100 //-----------------------------------------------------------------------------
101 
Transaction(HttpCache * cache)102 HttpCache::Transaction::Transaction(HttpCache* cache)
103     : next_state_(STATE_NONE),
104       request_(NULL),
105       cache_(cache->AsWeakPtr()),
106       entry_(NULL),
107       new_entry_(NULL),
108       network_trans_(NULL),
109       callback_(NULL),
110       new_response_(NULL),
111       mode_(NONE),
112       target_state_(STATE_NONE),
113       reading_(false),
114       invalid_range_(false),
115       truncated_(false),
116       is_sparse_(false),
117       server_responded_206_(false),
118       cache_pending_(false),
119       read_offset_(0),
120       effective_load_flags_(0),
121       write_len_(0),
122       final_upload_progress_(0),
123       ALLOW_THIS_IN_INITIALIZER_LIST(
124           io_callback_(this, &Transaction::OnIOComplete)),
125       ALLOW_THIS_IN_INITIALIZER_LIST(
126           cache_callback_(new CancelableCompletionCallback<Transaction>(
127               this, &Transaction::OnIOComplete))),
128       ALLOW_THIS_IN_INITIALIZER_LIST(
129           write_headers_callback_(new CancelableCompletionCallback<Transaction>(
130               this, &Transaction::OnIOComplete))) {
131   COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
132                  arraysize(kValidationHeaders),
133                  Invalid_number_of_validation_headers);
134 }
135 
~Transaction()136 HttpCache::Transaction::~Transaction() {
137   // We may have to issue another IO, but we should never invoke the callback_
138   // after this point.
139   callback_ = NULL;
140 
141   if (cache_) {
142     if (entry_) {
143       bool cancel_request = reading_;
144       if (cancel_request) {
145         if (partial_.get()) {
146           entry_->disk_entry->CancelSparseIO();
147         } else {
148           cancel_request &= (response_.headers->response_code() == 200);
149         }
150       }
151 
152       cache_->DoneWithEntry(entry_, this, cancel_request);
153     } else if (cache_pending_) {
154       cache_->RemovePendingTransaction(this);
155     }
156   }
157 
158   // If there is an outstanding callback, mark it as cancelled so running it
159   // does nothing.
160   cache_callback_->Cancel();
161   write_headers_callback_->Cancel();
162 
163   // We could still have a cache read or write in progress, so we just null the
164   // cache_ pointer to signal that we are dead.  See DoCacheReadCompleted.
165   cache_.reset();
166 }
167 
WriteMetadata(IOBuffer * buf,int buf_len,CompletionCallback * callback)168 int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
169                                           CompletionCallback* callback) {
170   DCHECK(buf);
171   DCHECK_GT(buf_len, 0);
172   DCHECK(callback);
173   if (!cache_ || !entry_)
174     return ERR_UNEXPECTED;
175 
176   // We don't need to track this operation for anything.
177   // It could be possible to check if there is something already written and
178   // avoid writing again (it should be the same, right?), but let's allow the
179   // caller to "update" the contents with something new.
180   return entry_->disk_entry->WriteData(kMetadataIndex, 0, buf, buf_len,
181                                        callback, true);
182 }
183 
AddTruncatedFlag()184 bool HttpCache::Transaction::AddTruncatedFlag() {
185   DCHECK(mode_ & WRITE);
186 
187   // Don't set the flag for sparse entries.
188   if (partial_.get() && !truncated_)
189     return true;
190 
191   if (!CanResume(true))
192     return false;
193 
194   truncated_ = true;
195   target_state_ = STATE_NONE;
196   next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE;
197   DoLoop(OK);
198   return true;
199 }
200 
GetWriterLoadState() const201 LoadState HttpCache::Transaction::GetWriterLoadState() const {
202   if (network_trans_.get())
203     return network_trans_->GetLoadState();
204   if (entry_ || !request_)
205     return LOAD_STATE_IDLE;
206   return LOAD_STATE_WAITING_FOR_CACHE;
207 }
208 
net_log() const209 const BoundNetLog& HttpCache::Transaction::net_log() const {
210   return net_log_;
211 }
212 
Start(const HttpRequestInfo * request,CompletionCallback * callback,const BoundNetLog & net_log)213 int HttpCache::Transaction::Start(const HttpRequestInfo* request,
214                                   CompletionCallback* callback,
215                                   const BoundNetLog& net_log) {
216   DCHECK(request);
217   DCHECK(callback);
218 
219   // Ensure that we only have one asynchronous call at a time.
220   DCHECK(!callback_);
221   DCHECK(!reading_);
222   DCHECK(!network_trans_.get());
223   DCHECK(!entry_);
224 
225   if (!cache_)
226     return ERR_UNEXPECTED;
227 
228   SetRequest(net_log, request);
229 
230   // We have to wait until the backend is initialized so we start the SM.
231   next_state_ = STATE_GET_BACKEND;
232   int rv = DoLoop(OK);
233 
234   // Setting this here allows us to check for the existence of a callback_ to
235   // determine if we are still inside Start.
236   if (rv == ERR_IO_PENDING)
237     callback_ = callback;
238 
239   return rv;
240 }
241 
RestartIgnoringLastError(CompletionCallback * callback)242 int HttpCache::Transaction::RestartIgnoringLastError(
243     CompletionCallback* callback) {
244   DCHECK(callback);
245 
246   // Ensure that we only have one asynchronous call at a time.
247   DCHECK(!callback_);
248 
249   if (!cache_)
250     return ERR_UNEXPECTED;
251 
252   int rv = RestartNetworkRequest();
253 
254   if (rv == ERR_IO_PENDING)
255     callback_ = callback;
256 
257   return rv;
258 }
259 
RestartWithCertificate(X509Certificate * client_cert,CompletionCallback * callback)260 int HttpCache::Transaction::RestartWithCertificate(
261     X509Certificate* client_cert,
262     CompletionCallback* callback) {
263   DCHECK(callback);
264 
265   // Ensure that we only have one asynchronous call at a time.
266   DCHECK(!callback_);
267 
268   if (!cache_)
269     return ERR_UNEXPECTED;
270 
271   int rv = RestartNetworkRequestWithCertificate(client_cert);
272 
273   if (rv == ERR_IO_PENDING)
274     callback_ = callback;
275 
276   return rv;
277 }
278 
RestartWithAuth(const string16 & username,const string16 & password,CompletionCallback * callback)279 int HttpCache::Transaction::RestartWithAuth(
280     const string16& username,
281     const string16& password,
282     CompletionCallback* callback) {
283   DCHECK(auth_response_.headers);
284   DCHECK(callback);
285 
286   // Ensure that we only have one asynchronous call at a time.
287   DCHECK(!callback_);
288 
289   if (!cache_)
290     return ERR_UNEXPECTED;
291 
292   // Clear the intermediate response since we are going to start over.
293   auth_response_ = HttpResponseInfo();
294 
295   int rv = RestartNetworkRequestWithAuth(username, password);
296 
297   if (rv == ERR_IO_PENDING)
298     callback_ = callback;
299 
300   return rv;
301 }
302 
IsReadyToRestartForAuth()303 bool HttpCache::Transaction::IsReadyToRestartForAuth() {
304   if (!network_trans_.get())
305     return false;
306   return network_trans_->IsReadyToRestartForAuth();
307 }
308 
Read(IOBuffer * buf,int buf_len,CompletionCallback * callback)309 int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
310                                  CompletionCallback* callback) {
311   DCHECK(buf);
312   DCHECK_GT(buf_len, 0);
313   DCHECK(callback);
314 
315   DCHECK(!callback_);
316 
317   if (!cache_)
318     return ERR_UNEXPECTED;
319 
320   // If we have an intermediate auth response at this point, then it means the
321   // user wishes to read the network response (the error page).  If there is a
322   // previous response in the cache then we should leave it intact.
323   if (auth_response_.headers && mode_ != NONE) {
324     DCHECK(mode_ & WRITE);
325     DoneWritingToEntry(mode_ == READ_WRITE);
326     mode_ = NONE;
327   }
328 
329   reading_ = true;
330   int rv;
331 
332   switch (mode_) {
333     case READ_WRITE:
334       DCHECK(partial_.get());
335       if (!network_trans_.get()) {
336         // We are just reading from the cache, but we may be writing later.
337         rv = ReadFromEntry(buf, buf_len);
338         break;
339       }
340     case NONE:
341     case WRITE:
342       DCHECK(network_trans_.get());
343       rv = ReadFromNetwork(buf, buf_len);
344       break;
345     case READ:
346       rv = ReadFromEntry(buf, buf_len);
347       break;
348     default:
349       NOTREACHED();
350       rv = ERR_FAILED;
351   }
352 
353   if (rv == ERR_IO_PENDING) {
354     DCHECK(!callback_);
355     callback_ = callback;
356   }
357   return rv;
358 }
359 
StopCaching()360 void HttpCache::Transaction::StopCaching() {
361 }
362 
GetResponseInfo() const363 const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {
364   // Null headers means we encountered an error or haven't a response yet
365   if (auth_response_.headers)
366     return &auth_response_;
367   return (response_.headers || response_.ssl_info.cert ||
368           response_.cert_request_info) ? &response_ : NULL;
369 }
370 
GetLoadState() const371 LoadState HttpCache::Transaction::GetLoadState() const {
372   LoadState state = GetWriterLoadState();
373   if (state != LOAD_STATE_WAITING_FOR_CACHE)
374     return state;
375 
376   if (cache_)
377     return cache_->GetLoadStateForPendingTransaction(this);
378 
379   return LOAD_STATE_IDLE;
380 }
381 
GetUploadProgress() const382 uint64 HttpCache::Transaction::GetUploadProgress() const {
383   if (network_trans_.get())
384     return network_trans_->GetUploadProgress();
385   return final_upload_progress_;
386 }
387 
388 //-----------------------------------------------------------------------------
389 
DoCallback(int rv)390 void HttpCache::Transaction::DoCallback(int rv) {
391   DCHECK(rv != ERR_IO_PENDING);
392   DCHECK(callback_);
393 
394   // Since Run may result in Read being called, clear callback_ up front.
395   CompletionCallback* c = callback_;
396   callback_ = NULL;
397   c->Run(rv);
398 }
399 
HandleResult(int rv)400 int HttpCache::Transaction::HandleResult(int rv) {
401   DCHECK(rv != ERR_IO_PENDING);
402   if (callback_)
403     DoCallback(rv);
404   return rv;
405 }
406 
DoLoop(int result)407 int HttpCache::Transaction::DoLoop(int result) {
408   DCHECK(next_state_ != STATE_NONE);
409 
410   int rv = result;
411   do {
412     State state = next_state_;
413     next_state_ = STATE_NONE;
414     switch (state) {
415       case STATE_GET_BACKEND:
416         DCHECK_EQ(OK, rv);
417         rv = DoGetBackend();
418         break;
419       case STATE_GET_BACKEND_COMPLETE:
420         rv = DoGetBackendComplete(rv);
421         break;
422       case STATE_SEND_REQUEST:
423         DCHECK_EQ(OK, rv);
424         rv = DoSendRequest();
425         break;
426       case STATE_SEND_REQUEST_COMPLETE:
427         rv = DoSendRequestComplete(rv);
428         break;
429       case STATE_SUCCESSFUL_SEND_REQUEST:
430         DCHECK_EQ(OK, rv);
431         rv = DoSuccessfulSendRequest();
432         break;
433       case STATE_NETWORK_READ:
434         DCHECK_EQ(OK, rv);
435         rv = DoNetworkRead();
436         break;
437       case STATE_NETWORK_READ_COMPLETE:
438         rv = DoNetworkReadComplete(rv);
439         break;
440       case STATE_INIT_ENTRY:
441         DCHECK_EQ(OK, rv);
442         rv = DoInitEntry();
443         break;
444       case STATE_OPEN_ENTRY:
445         DCHECK_EQ(OK, rv);
446         rv = DoOpenEntry();
447         break;
448       case STATE_OPEN_ENTRY_COMPLETE:
449         rv = DoOpenEntryComplete(rv);
450         break;
451       case STATE_CREATE_ENTRY:
452         DCHECK_EQ(OK, rv);
453         rv = DoCreateEntry();
454         break;
455       case STATE_CREATE_ENTRY_COMPLETE:
456         rv = DoCreateEntryComplete(rv);
457         break;
458       case STATE_DOOM_ENTRY:
459         DCHECK_EQ(OK, rv);
460         rv = DoDoomEntry();
461         break;
462       case STATE_DOOM_ENTRY_COMPLETE:
463         rv = DoDoomEntryComplete(rv);
464         break;
465       case STATE_ADD_TO_ENTRY:
466         DCHECK_EQ(OK, rv);
467         rv = DoAddToEntry();
468         break;
469       case STATE_ADD_TO_ENTRY_COMPLETE:
470         rv = DoAddToEntryComplete(rv);
471         break;
472       case STATE_NOTIFY_BEFORE_SEND_HEADERS:
473         DCHECK_EQ(OK, rv);
474         rv = DoNotifyBeforeSendHeaders();
475         break;
476       case STATE_NOTIFY_BEFORE_SEND_HEADERS_COMPLETE:
477         rv = DoNotifyBeforeSendHeadersComplete(rv);
478         break;
479       case STATE_START_PARTIAL_CACHE_VALIDATION:
480         DCHECK_EQ(OK, rv);
481         rv = DoStartPartialCacheValidation();
482         break;
483       case STATE_COMPLETE_PARTIAL_CACHE_VALIDATION:
484         rv = DoCompletePartialCacheValidation(rv);
485         break;
486       case STATE_UPDATE_CACHED_RESPONSE:
487         DCHECK_EQ(OK, rv);
488         rv = DoUpdateCachedResponse();
489         break;
490       case STATE_UPDATE_CACHED_RESPONSE_COMPLETE:
491         rv = DoUpdateCachedResponseComplete(rv);
492         break;
493       case STATE_OVERWRITE_CACHED_RESPONSE:
494         DCHECK_EQ(OK, rv);
495         rv = DoOverwriteCachedResponse();
496         break;
497       case STATE_TRUNCATE_CACHED_DATA:
498         DCHECK_EQ(OK, rv);
499         rv = DoTruncateCachedData();
500         break;
501       case STATE_TRUNCATE_CACHED_DATA_COMPLETE:
502         rv = DoTruncateCachedDataComplete(rv);
503         break;
504       case STATE_TRUNCATE_CACHED_METADATA:
505         DCHECK_EQ(OK, rv);
506         rv = DoTruncateCachedMetadata();
507         break;
508       case STATE_TRUNCATE_CACHED_METADATA_COMPLETE:
509         rv = DoTruncateCachedMetadataComplete(rv);
510         break;
511       case STATE_PARTIAL_HEADERS_RECEIVED:
512         DCHECK_EQ(OK, rv);
513         rv = DoPartialHeadersReceived();
514         break;
515       case STATE_CACHE_READ_RESPONSE:
516         DCHECK_EQ(OK, rv);
517         rv = DoCacheReadResponse();
518         break;
519       case STATE_CACHE_READ_RESPONSE_COMPLETE:
520         rv = DoCacheReadResponseComplete(rv);
521         break;
522       case STATE_CACHE_WRITE_RESPONSE:
523         DCHECK_EQ(OK, rv);
524         rv = DoCacheWriteResponse();
525         break;
526       case STATE_CACHE_WRITE_TRUNCATED_RESPONSE:
527         DCHECK_EQ(OK, rv);
528         rv = DoCacheWriteTruncatedResponse();
529         break;
530       case STATE_CACHE_WRITE_RESPONSE_COMPLETE:
531         rv = DoCacheWriteResponseComplete(rv);
532         break;
533       case STATE_CACHE_READ_METADATA:
534         DCHECK_EQ(OK, rv);
535         rv = DoCacheReadMetadata();
536         break;
537       case STATE_CACHE_READ_METADATA_COMPLETE:
538         rv = DoCacheReadMetadataComplete(rv);
539         break;
540       case STATE_CACHE_QUERY_DATA:
541         DCHECK_EQ(OK, rv);
542         rv = DoCacheQueryData();
543         break;
544       case STATE_CACHE_QUERY_DATA_COMPLETE:
545         rv = DoCacheQueryDataComplete(rv);
546         break;
547       case STATE_CACHE_READ_DATA:
548         DCHECK_EQ(OK, rv);
549         rv = DoCacheReadData();
550         break;
551       case STATE_CACHE_READ_DATA_COMPLETE:
552         rv = DoCacheReadDataComplete(rv);
553         break;
554       case STATE_CACHE_WRITE_DATA:
555         rv = DoCacheWriteData(rv);
556         break;
557       case STATE_CACHE_WRITE_DATA_COMPLETE:
558         rv = DoCacheWriteDataComplete(rv);
559         break;
560       default:
561         NOTREACHED() << "bad state";
562         rv = ERR_FAILED;
563         break;
564     }
565   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
566 
567   if (rv != ERR_IO_PENDING)
568     HandleResult(rv);
569 
570   return rv;
571 }
572 
DoGetBackend()573 int HttpCache::Transaction::DoGetBackend() {
574   cache_pending_ = true;
575   next_state_ = STATE_GET_BACKEND_COMPLETE;
576   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_GET_BACKEND, NULL);
577   return cache_->GetBackendForTransaction(this);
578 }
579 
DoGetBackendComplete(int result)580 int HttpCache::Transaction::DoGetBackendComplete(int result) {
581   DCHECK(result == OK || result == ERR_FAILED);
582   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_GET_BACKEND,
583                                     result);
584   cache_pending_ = false;
585 
586   if (!ShouldPassThrough()) {
587     cache_key_ = cache_->GenerateCacheKey(request_);
588 
589     // Requested cache access mode.
590     if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
591       mode_ = READ;
592     } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
593       mode_ = WRITE;
594     } else {
595       mode_ = READ_WRITE;
596     }
597 
598     // Downgrade to UPDATE if the request has been externally conditionalized.
599     if (external_validation_.initialized) {
600       if (mode_ & WRITE) {
601         // Strip off the READ_DATA bit (and maybe add back a READ_META bit
602         // in case READ was off).
603         mode_ = UPDATE;
604       } else {
605         mode_ = NONE;
606       }
607     }
608   }
609 
610   // If must use cache, then we must fail.  This can happen for back/forward
611   // navigations to a page generated via a form post.
612   if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE)
613     return ERR_CACHE_MISS;
614 
615   if (mode_ == NONE) {
616     if (partial_.get())
617       partial_->RestoreHeaders(&custom_request_->extra_headers);
618     next_state_ = STATE_SEND_REQUEST;
619   } else {
620     next_state_ = STATE_INIT_ENTRY;
621   }
622 
623   return OK;
624 }
625 
DoSendRequest()626 int HttpCache::Transaction::DoSendRequest() {
627   DCHECK(mode_ & WRITE || mode_ == NONE);
628   DCHECK(!network_trans_.get());
629 
630   // Create a network transaction.
631   int rv = cache_->network_layer_->CreateTransaction(&network_trans_);
632   if (rv != OK)
633     return rv;
634 
635   next_state_ = STATE_SEND_REQUEST_COMPLETE;
636   rv = network_trans_->Start(request_, &io_callback_, net_log_);
637   return rv;
638 }
639 
DoSendRequestComplete(int result)640 int HttpCache::Transaction::DoSendRequestComplete(int result) {
641   if (!cache_)
642     return ERR_UNEXPECTED;
643 
644   if (result == OK) {
645     next_state_ = STATE_SUCCESSFUL_SEND_REQUEST;
646     return OK;
647   }
648 
649   if (IsCertificateError(result)) {
650     const HttpResponseInfo* response = network_trans_->GetResponseInfo();
651     // If we get a certificate error, then there is a certificate in ssl_info,
652     // so GetResponseInfo() should never returns NULL here.
653     DCHECK(response);
654     response_.ssl_info = response->ssl_info;
655   } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
656     const HttpResponseInfo* response = network_trans_->GetResponseInfo();
657     DCHECK(response);
658     response_.cert_request_info = response->cert_request_info;
659   }
660   return result;
661 }
662 
663 // We received the response headers and there is no error.
DoSuccessfulSendRequest()664 int HttpCache::Transaction::DoSuccessfulSendRequest() {
665   DCHECK(!new_response_);
666   const HttpResponseInfo* new_response = network_trans_->GetResponseInfo();
667   if (new_response->headers->response_code() == 401 ||
668       new_response->headers->response_code() == 407) {
669     auth_response_ = *new_response;
670     return OK;
671   }
672 
673   new_response_ = new_response;
674   if (!ValidatePartialResponse(&server_responded_206_) &&
675       !auth_response_.headers) {
676     // Something went wrong with this request and we have to restart it.
677     // If we have an authentication response, we are exposed to weird things
678     // hapenning if the user cancels the authentication before we receive
679     // the new response.
680     response_ = HttpResponseInfo();
681     network_trans_.reset();
682     new_response_ = NULL;
683     next_state_ = STATE_SEND_REQUEST;
684     return OK;
685   }
686   if (server_responded_206_ && mode_ == READ_WRITE && !truncated_ &&
687       !is_sparse_) {
688     // We have stored the full entry, but it changed and the server is
689     // sending a range. We have to delete the old entry.
690     DoneWritingToEntry(false);
691   }
692 
693   if (new_response_->headers->response_code() == 416) {
694     DCHECK_EQ(NONE, mode_);
695     response_ = *new_response_;
696     return OK;
697   }
698 
699   // Are we expecting a response to a conditional query?
700   if (mode_ == READ_WRITE || mode_ == UPDATE) {
701     if (new_response->headers->response_code() == 304 ||
702         server_responded_206_) {
703       next_state_ = STATE_UPDATE_CACHED_RESPONSE;
704       return OK;
705     }
706     mode_ = WRITE;
707   }
708 
709   next_state_ = STATE_OVERWRITE_CACHED_RESPONSE;
710   return OK;
711 }
712 
DoNetworkRead()713 int HttpCache::Transaction::DoNetworkRead() {
714   next_state_ = STATE_NETWORK_READ_COMPLETE;
715   return network_trans_->Read(read_buf_, io_buf_len_, &io_callback_);
716 }
717 
DoNetworkReadComplete(int result)718 int HttpCache::Transaction::DoNetworkReadComplete(int result) {
719   DCHECK(mode_ & WRITE || mode_ == NONE);
720 
721   if (!cache_)
722     return ERR_UNEXPECTED;
723 
724   // If there is an error and we are saving the data, just tell the user about
725   // it and wait until the destructor runs to see if we can keep the data.
726   if (mode_ != NONE && result < 0)
727     return result;
728 
729   next_state_ = STATE_CACHE_WRITE_DATA;
730   return result;
731 }
732 
DoInitEntry()733 int HttpCache::Transaction::DoInitEntry() {
734   DCHECK(!new_entry_);
735 
736   if (!cache_)
737     return ERR_UNEXPECTED;
738 
739   if (mode_ == WRITE) {
740     next_state_ = STATE_DOOM_ENTRY;
741     return OK;
742   }
743 
744   next_state_ = STATE_OPEN_ENTRY;
745   return OK;
746 }
747 
DoOpenEntry()748 int HttpCache::Transaction::DoOpenEntry() {
749   DCHECK(!new_entry_);
750   next_state_ = STATE_OPEN_ENTRY_COMPLETE;
751   cache_pending_ = true;
752   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, NULL);
753   return cache_->OpenEntry(cache_key_, &new_entry_, this);
754 }
755 
DoOpenEntryComplete(int result)756 int HttpCache::Transaction::DoOpenEntryComplete(int result) {
757   // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
758   // OK, otherwise the cache will end up with an active entry without any
759   // transaction attached.
760   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result);
761   cache_pending_ = false;
762   if (result == OK) {
763     next_state_ = STATE_ADD_TO_ENTRY;
764     return OK;
765   }
766 
767   if (result == ERR_CACHE_RACE) {
768     next_state_ = STATE_INIT_ENTRY;
769     return OK;
770   }
771 
772   if (mode_ == READ_WRITE) {
773     mode_ = WRITE;
774     next_state_ = STATE_CREATE_ENTRY;
775     return OK;
776   }
777   if (mode_ == UPDATE) {
778     // There is no cache entry to update; proceed without caching.
779     mode_ = NONE;
780     next_state_ = STATE_SEND_REQUEST;
781     return OK;
782   }
783   if (cache_->mode() == PLAYBACK)
784     DVLOG(1) << "Playback Cache Miss: " << request_->url;
785 
786   // The entry does not exist, and we are not permitted to create a new entry,
787   // so we must fail.
788   return ERR_CACHE_MISS;
789 }
790 
DoCreateEntry()791 int HttpCache::Transaction::DoCreateEntry() {
792   DCHECK(!new_entry_);
793   next_state_ = STATE_CREATE_ENTRY_COMPLETE;
794   cache_pending_ = true;
795   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY, NULL);
796   return cache_->CreateEntry(cache_key_, &new_entry_, this);
797 }
798 
DoCreateEntryComplete(int result)799 int HttpCache::Transaction::DoCreateEntryComplete(int result) {
800   // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
801   // OK, otherwise the cache will end up with an active entry without any
802   // transaction attached.
803   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY,
804                                     result);
805   cache_pending_ = false;
806   next_state_ = STATE_ADD_TO_ENTRY;
807 
808   if (result == ERR_CACHE_RACE) {
809     next_state_ = STATE_INIT_ENTRY;
810     return OK;
811   }
812 
813   if (result != OK) {
814     // We have a race here: Maybe we failed to open the entry and decided to
815     // create one, but by the time we called create, another transaction already
816     // created the entry. If we want to eliminate this issue, we need an atomic
817     // OpenOrCreate() method exposed by the disk cache.
818     DLOG(WARNING) << "Unable to create cache entry";
819     mode_ = NONE;
820     if (partial_.get())
821       partial_->RestoreHeaders(&custom_request_->extra_headers);
822     next_state_ = STATE_SEND_REQUEST;
823   }
824   return OK;
825 }
826 
DoDoomEntry()827 int HttpCache::Transaction::DoDoomEntry() {
828   next_state_ = STATE_DOOM_ENTRY_COMPLETE;
829   cache_pending_ = true;
830   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, NULL);
831   return cache_->DoomEntry(cache_key_, this);
832 }
833 
DoDoomEntryComplete(int result)834 int HttpCache::Transaction::DoDoomEntryComplete(int result) {
835   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result);
836   next_state_ = STATE_CREATE_ENTRY;
837   cache_pending_ = false;
838   if (result == ERR_CACHE_RACE)
839     next_state_ = STATE_INIT_ENTRY;
840 
841   return OK;
842 }
843 
DoAddToEntry()844 int HttpCache::Transaction::DoAddToEntry() {
845   DCHECK(new_entry_);
846   cache_pending_ = true;
847   next_state_ = STATE_ADD_TO_ENTRY_COMPLETE;
848   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY, NULL);
849   DCHECK(entry_lock_waiting_since_.is_null());
850   entry_lock_waiting_since_ = base::TimeTicks::Now();
851   return cache_->AddTransactionToEntry(new_entry_, this);
852 }
853 
DoAddToEntryComplete(int result)854 int HttpCache::Transaction::DoAddToEntryComplete(int result) {
855   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY,
856                                     result);
857 
858   const base::TimeDelta entry_lock_wait =
859       base::TimeTicks::Now() - entry_lock_waiting_since_;
860   UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait);
861   static const bool prefetching_fieldtrial =
862       base::FieldTrialList::Find("Prefetch") &&
863       !base::FieldTrialList::Find("Prefetch")->group_name().empty();
864   if (prefetching_fieldtrial) {
865     UMA_HISTOGRAM_TIMES(
866         base::FieldTrial::MakeName("HttpCache.EntryLockWait", "Prefetch"),
867         entry_lock_wait);
868   }
869 
870   entry_lock_waiting_since_ = base::TimeTicks();
871   DCHECK(new_entry_);
872   cache_pending_ = false;
873 
874   if (result == ERR_CACHE_RACE) {
875     new_entry_ = NULL;
876     next_state_ = STATE_INIT_ENTRY;
877     return OK;
878   }
879 
880   if (result != OK) {
881     // If there is a failure, the cache should have taken care of new_entry_.
882     NOTREACHED();
883     new_entry_ = NULL;
884     return result;
885   }
886 
887   entry_ = new_entry_;
888   new_entry_ = NULL;
889 
890   if (mode_ == WRITE) {
891     if (partial_.get())
892       partial_->RestoreHeaders(&custom_request_->extra_headers);
893     next_state_ = STATE_SEND_REQUEST;
894   } else {
895     // We have to read the headers from the cached entry.
896     DCHECK(mode_ & READ_META);
897     next_state_ = STATE_CACHE_READ_RESPONSE;
898   }
899   return OK;
900 }
901 
DoNotifyBeforeSendHeaders()902 int HttpCache::Transaction::DoNotifyBeforeSendHeaders() {
903   // Balanced in DoNotifyBeforeSendHeadersComplete.
904   cache_callback_->AddRef();
905   next_state_ = STATE_NOTIFY_BEFORE_SEND_HEADERS_COMPLETE;
906 
907   if (cache_->GetSession() && cache_->GetSession()->network_delegate()) {
908     // TODO(mpcomplete): need to be able to modify these headers.
909     HttpRequestHeaders headers = request_->extra_headers;
910     return cache_->GetSession()->network_delegate()->NotifyBeforeSendHeaders(
911         request_->request_id, cache_callback_, &headers);
912   }
913 
914   return OK;
915 }
916 
DoNotifyBeforeSendHeadersComplete(int result)917 int HttpCache::Transaction::DoNotifyBeforeSendHeadersComplete(int result) {
918   cache_callback_->Release();  // Balanced in DoNotifyBeforeSendHeaders.
919 
920   // We now have access to the cache entry.
921   //
922   //  o if we are a reader for the transaction, then we can start reading the
923   //    cache entry.
924   //
925   //  o if we can read or write, then we should check if the cache entry needs
926   //    to be validated and then issue a network request if needed or just read
927   //    from the cache if the cache entry is already valid.
928   //
929   //  o if we are set to UPDATE, then we are handling an externally
930   //    conditionalized request (if-modified-since / if-none-match). We check
931   //    if the request headers define a validation request.
932   //
933   if (result == net::OK) {
934     switch (mode_) {
935       case READ:
936         result = BeginCacheRead();
937         break;
938       case READ_WRITE:
939         result = BeginPartialCacheValidation();
940         break;
941       case UPDATE:
942         result = BeginExternallyConditionalizedRequest();
943         break;
944       case WRITE:
945       default:
946         NOTREACHED();
947         result = ERR_FAILED;
948     }
949   }
950   return result;
951 }
952 
953 // We may end up here multiple times for a given request.
DoStartPartialCacheValidation()954 int HttpCache::Transaction::DoStartPartialCacheValidation() {
955   if (mode_ == NONE)
956     return OK;
957 
958   next_state_ = STATE_COMPLETE_PARTIAL_CACHE_VALIDATION;
959   return partial_->ShouldValidateCache(entry_->disk_entry, &io_callback_);
960 }
961 
DoCompletePartialCacheValidation(int result)962 int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
963   if (!result) {
964     // This is the end of the request.
965     if (mode_ & WRITE) {
966       DoneWritingToEntry(true);
967     } else {
968       cache_->DoneReadingFromEntry(entry_, this);
969       entry_ = NULL;
970     }
971     return result;
972   }
973 
974   if (result < 0)
975     return result;
976 
977   partial_->PrepareCacheValidation(entry_->disk_entry,
978                                    &custom_request_->extra_headers);
979 
980   if (reading_ && partial_->IsCurrentRangeCached()) {
981     next_state_ = STATE_CACHE_READ_DATA;
982     return OK;
983   }
984 
985   return BeginCacheValidation();
986 }
987 
988 // We received 304 or 206 and we want to update the cached response headers.
DoUpdateCachedResponse()989 int HttpCache::Transaction::DoUpdateCachedResponse() {
990   next_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE;
991   int rv = OK;
992   // Update cached response based on headers in new_response.
993   // TODO(wtc): should we update cached certificate (response_.ssl_info), too?
994   response_.headers->Update(*new_response_->headers);
995   response_.response_time = new_response_->response_time;
996   response_.request_time = new_response_->request_time;
997 
998   if (response_.headers->HasHeaderValue("cache-control", "no-store")) {
999     int ret = cache_->DoomEntry(cache_key_, NULL);
1000     DCHECK_EQ(OK, ret);
1001   } else {
1002     // If we are already reading, we already updated the headers for this
1003     // request; doing it again will change Content-Length.
1004     if (!reading_) {
1005       target_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE;
1006       next_state_ = STATE_CACHE_WRITE_RESPONSE;
1007       rv = OK;
1008     }
1009   }
1010   return rv;
1011 }
1012 
DoUpdateCachedResponseComplete(int result)1013 int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
1014   if (mode_ == UPDATE) {
1015     DCHECK(!server_responded_206_);
1016     // We got a "not modified" response and already updated the corresponding
1017     // cache entry above.
1018     //
1019     // By closing the cached entry now, we make sure that the 304 rather than
1020     // the cached 200 response, is what will be returned to the user.
1021     DoneWritingToEntry(true);
1022   } else if (entry_ && !server_responded_206_) {
1023     DCHECK_EQ(READ_WRITE, mode_);
1024     if (!partial_.get() || partial_->IsLastRange()) {
1025       cache_->ConvertWriterToReader(entry_);
1026       mode_ = READ;
1027     }
1028     // We no longer need the network transaction, so destroy it.
1029     final_upload_progress_ = network_trans_->GetUploadProgress();
1030     network_trans_.reset();
1031   } else if (entry_ && server_responded_206_ && truncated_ &&
1032              partial_->initial_validation()) {
1033     // We just finished the validation of a truncated entry, and the server
1034     // is willing to resume the operation. Now we go back and start serving
1035     // the first part to the user.
1036     network_trans_.reset();
1037     new_response_ = NULL;
1038     next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
1039     partial_->SetRangeToStartDownload();
1040     return OK;
1041   }
1042   next_state_ = STATE_OVERWRITE_CACHED_RESPONSE;
1043   return OK;
1044 }
1045 
DoOverwriteCachedResponse()1046 int HttpCache::Transaction::DoOverwriteCachedResponse() {
1047   if (mode_ & READ) {
1048     next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
1049     return OK;
1050   }
1051 
1052   // We change the value of Content-Length for partial content.
1053   if (server_responded_206_ && partial_.get())
1054     partial_->FixContentLength(new_response_->headers);
1055 
1056   response_ = *new_response_;
1057 
1058   if (server_responded_206_ && !CanResume(false)) {
1059     // There is no point in storing this resource because it will never be used.
1060     DoneWritingToEntry(false);
1061     if (partial_.get())
1062       partial_->FixResponseHeaders(response_.headers, true);
1063     next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
1064     return OK;
1065   }
1066 
1067   target_state_ = STATE_TRUNCATE_CACHED_DATA;
1068   next_state_ = truncated_ ? STATE_CACHE_WRITE_TRUNCATED_RESPONSE :
1069                              STATE_CACHE_WRITE_RESPONSE;
1070   return OK;
1071 }
1072 
DoTruncateCachedData()1073 int HttpCache::Transaction::DoTruncateCachedData() {
1074   next_state_ = STATE_TRUNCATE_CACHED_DATA_COMPLETE;
1075   cache_callback_->AddRef();  // Balanced in DoTruncateCachedDataComplete.
1076   if (!entry_)
1077     return OK;
1078   if (net_log_.IsLoggingAllEvents())
1079     net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA, NULL);
1080 
1081   // Truncate the stream.
1082   return WriteToEntry(kResponseContentIndex, 0, NULL, 0, cache_callback_);
1083 }
1084 
DoTruncateCachedDataComplete(int result)1085 int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
1086   if (net_log_.IsLoggingAllEvents() && entry_) {
1087     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
1088                                       result);
1089   }
1090 
1091   // Balance the AddRef from DoTruncateCachedData.
1092   cache_callback_->Release();
1093   next_state_ = STATE_TRUNCATE_CACHED_METADATA;
1094   return OK;
1095 }
1096 
DoTruncateCachedMetadata()1097 int HttpCache::Transaction::DoTruncateCachedMetadata() {
1098   next_state_ = STATE_TRUNCATE_CACHED_METADATA_COMPLETE;
1099   cache_callback_->AddRef();  // Balanced in DoTruncateCachedMetadataComplete.
1100   if (!entry_)
1101     return OK;
1102 
1103   if (net_log_.IsLoggingAllEvents())
1104     net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, NULL);
1105   return WriteToEntry(kMetadataIndex, 0, NULL, 0, cache_callback_);
1106 }
1107 
DoTruncateCachedMetadataComplete(int result)1108 int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) {
1109   if (net_log_.IsLoggingAllEvents() && entry_) {
1110     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
1111                                       result);
1112   }
1113 
1114   // Balance the AddRef from DoTruncateCachedMetadata.
1115   cache_callback_->Release();
1116 
1117   // If this response is a redirect, then we can stop writing now.  (We don't
1118   // need to cache the response body of a redirect.)
1119   if (response_.headers->IsRedirect(NULL))
1120     DoneWritingToEntry(true);
1121   next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
1122   return OK;
1123 }
1124 
DoPartialHeadersReceived()1125 int HttpCache::Transaction::DoPartialHeadersReceived() {
1126   new_response_ = NULL;
1127   if (entry_ && !partial_.get() &&
1128       entry_->disk_entry->GetDataSize(kMetadataIndex))
1129     next_state_ = STATE_CACHE_READ_METADATA;
1130 
1131   if (!partial_.get())
1132     return OK;
1133 
1134   if (reading_) {
1135     if (network_trans_.get()) {
1136       next_state_ = STATE_NETWORK_READ;
1137     } else {
1138       next_state_ = STATE_CACHE_READ_DATA;
1139     }
1140   } else if (mode_ != NONE) {
1141     // We are about to return the headers for a byte-range request to the user,
1142     // so let's fix them.
1143     partial_->FixResponseHeaders(response_.headers, true);
1144   }
1145   return OK;
1146 }
1147 
DoCacheReadResponse()1148 int HttpCache::Transaction::DoCacheReadResponse() {
1149   DCHECK(entry_);
1150   next_state_ = STATE_CACHE_READ_RESPONSE_COMPLETE;
1151 
1152   io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
1153   read_buf_ = new IOBuffer(io_buf_len_);
1154 
1155   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO, NULL);
1156   cache_callback_->AddRef();  // Balanced in DoCacheReadResponseComplete.
1157   return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_,
1158                                       io_buf_len_, cache_callback_);
1159 }
1160 
DoCacheReadResponseComplete(int result)1161 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
1162   cache_callback_->Release();  // Balance the AddRef from DoCacheReadResponse.
1163 
1164   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
1165   if (result != io_buf_len_ ||
1166       !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_,
1167                                     &response_, &truncated_)) {
1168     DLOG(ERROR) << "ReadData failed: " << result;
1169     return ERR_CACHE_READ_FAILURE;
1170   }
1171 
1172   next_state_ = STATE_NOTIFY_BEFORE_SEND_HEADERS;
1173   return OK;
1174 }
1175 
DoCacheWriteResponse()1176 int HttpCache::Transaction::DoCacheWriteResponse() {
1177   if (net_log_.IsLoggingAllEvents() && entry_)
1178     net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, NULL);
1179   return WriteResponseInfoToEntry(false);
1180 }
1181 
DoCacheWriteTruncatedResponse()1182 int HttpCache::Transaction::DoCacheWriteTruncatedResponse() {
1183   if (net_log_.IsLoggingAllEvents() && entry_)
1184     net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, NULL);
1185   return WriteResponseInfoToEntry(true);
1186 }
1187 
DoCacheWriteResponseComplete(int result)1188 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
1189   next_state_ = target_state_;
1190   target_state_ = STATE_NONE;
1191   if (!entry_)
1192     return OK;
1193   if (net_log_.IsLoggingAllEvents()) {
1194     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
1195                                       result);
1196   }
1197 
1198   // Balance the AddRef from WriteResponseInfoToEntry.
1199   write_headers_callback_->Release();
1200   if (result != io_buf_len_) {
1201     DLOG(ERROR) << "failed to write response info to cache";
1202     DoneWritingToEntry(false);
1203   }
1204   return OK;
1205 }
1206 
DoCacheReadMetadata()1207 int HttpCache::Transaction::DoCacheReadMetadata() {
1208   DCHECK(entry_);
1209   DCHECK(!response_.metadata);
1210   next_state_ = STATE_CACHE_READ_METADATA_COMPLETE;
1211 
1212   response_.metadata =
1213       new IOBufferWithSize(entry_->disk_entry->GetDataSize(kMetadataIndex));
1214 
1215   net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO, NULL);
1216   cache_callback_->AddRef();  // Balanced in DoCacheReadMetadataComplete.
1217   return entry_->disk_entry->ReadData(kMetadataIndex, 0, response_.metadata,
1218                                       response_.metadata->size(),
1219                                       cache_callback_);
1220 }
1221 
DoCacheReadMetadataComplete(int result)1222 int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
1223   cache_callback_->Release();  // Balance the AddRef from DoCacheReadMetadata.
1224   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
1225   if (result != response_.metadata->size()) {
1226     DLOG(ERROR) << "ReadData failed: " << result;
1227     return ERR_CACHE_READ_FAILURE;
1228   }
1229 
1230   return OK;
1231 }
1232 
DoCacheQueryData()1233 int HttpCache::Transaction::DoCacheQueryData() {
1234   next_state_ = STATE_CACHE_QUERY_DATA_COMPLETE;
1235 
1236   // Balanced in ValidateEntryHeadersAndContinue.
1237   cache_callback_->AddRef();
1238   return entry_->disk_entry->ReadyForSparseIO(cache_callback_);
1239 }
1240 
DoCacheQueryDataComplete(int result)1241 int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {
1242   DCHECK_EQ(OK, result);
1243   // Balance the AddRef from BeginPartialCacheValidation.
1244   cache_callback_->Release();
1245   if (!cache_)
1246     return ERR_UNEXPECTED;
1247 
1248   return ValidateEntryHeadersAndContinue(true);
1249 }
1250 
DoCacheReadData()1251 int HttpCache::Transaction::DoCacheReadData() {
1252   DCHECK(entry_);
1253   next_state_ = STATE_CACHE_READ_DATA_COMPLETE;
1254   cache_callback_->AddRef();  // Balanced in DoCacheReadDataComplete.
1255 
1256   if (net_log_.IsLoggingAllEvents())
1257     net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA, NULL);
1258   if (partial_.get()) {
1259     return partial_->CacheRead(entry_->disk_entry, read_buf_, io_buf_len_,
1260                                cache_callback_);
1261   }
1262 
1263   return entry_->disk_entry->ReadData(kResponseContentIndex, read_offset_,
1264                                       read_buf_, io_buf_len_, cache_callback_);
1265 }
1266 
DoCacheReadDataComplete(int result)1267 int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
1268   cache_callback_->Release();  // Balance the AddRef from DoCacheReadData.
1269   if (net_log_.IsLoggingAllEvents()) {
1270     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_DATA,
1271                                       result);
1272   }
1273 
1274   if (!cache_)
1275     return ERR_UNEXPECTED;
1276 
1277   if (partial_.get())
1278     return DoPartialCacheReadCompleted(result);
1279 
1280   if (result > 0) {
1281     read_offset_ += result;
1282   } else if (result == 0) {  // End of file.
1283     cache_->DoneReadingFromEntry(entry_, this);
1284     entry_ = NULL;
1285   }
1286   return result;
1287 }
1288 
DoCacheWriteData(int num_bytes)1289 int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
1290   next_state_ = STATE_CACHE_WRITE_DATA_COMPLETE;
1291   write_len_ = num_bytes;
1292   if (net_log_.IsLoggingAllEvents() && entry_)
1293     net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA, NULL);
1294   cache_callback_->AddRef();  // Balanced in DoCacheWriteDataComplete.
1295 
1296   return AppendResponseDataToEntry(read_buf_, num_bytes, cache_callback_);
1297 }
1298 
DoCacheWriteDataComplete(int result)1299 int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
1300   if (net_log_.IsLoggingAllEvents() && entry_) {
1301     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
1302                                       result);
1303   }
1304   // Balance the AddRef from DoCacheWriteData.
1305   cache_callback_->Release();
1306   if (!cache_)
1307     return ERR_UNEXPECTED;
1308 
1309   if (result != write_len_) {
1310     DLOG(ERROR) << "failed to write response data to cache";
1311     DoneWritingToEntry(false);
1312 
1313     // We want to ignore errors writing to disk and just keep reading from
1314     // the network.
1315     result = write_len_;
1316   }
1317 
1318   if (partial_.get()) {
1319     // This may be the last request.
1320     if (!(result == 0 && !truncated_ &&
1321           (partial_->IsLastRange() || mode_ == WRITE)))
1322       return DoPartialNetworkReadCompleted(result);
1323   }
1324 
1325   if (result == 0)  // End of file.
1326     DoneWritingToEntry(true);
1327 
1328   return result;
1329 }
1330 
1331 //-----------------------------------------------------------------------------
1332 
SetRequest(const BoundNetLog & net_log,const HttpRequestInfo * request)1333 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
1334                                         const HttpRequestInfo* request) {
1335   net_log_ = net_log;
1336   request_ = request;
1337   effective_load_flags_ = request_->load_flags;
1338 
1339   switch (cache_->mode()) {
1340     case NORMAL:
1341       break;
1342     case RECORD:
1343       // When in record mode, we want to NEVER load from the cache.
1344       // The reason for this is beacuse we save the Set-Cookie headers
1345       // (intentionally).  If we read from the cache, we replay them
1346       // prematurely.
1347       effective_load_flags_ |= LOAD_BYPASS_CACHE;
1348       break;
1349     case PLAYBACK:
1350       // When in playback mode, we want to load exclusively from the cache.
1351       effective_load_flags_ |= LOAD_ONLY_FROM_CACHE;
1352       break;
1353     case DISABLE:
1354       effective_load_flags_ |= LOAD_DISABLE_CACHE;
1355       break;
1356   }
1357 
1358   // Some headers imply load flags.  The order here is significant.
1359   //
1360   //   LOAD_DISABLE_CACHE   : no cache read or write
1361   //   LOAD_BYPASS_CACHE    : no cache read
1362   //   LOAD_VALIDATE_CACHE  : no cache read unless validation
1363   //
1364   // The former modes trump latter modes, so if we find a matching header we
1365   // can stop iterating kSpecialHeaders.
1366   //
1367   static const struct {
1368     const HeaderNameAndValue* search;
1369     int load_flag;
1370   } kSpecialHeaders[] = {
1371     { kPassThroughHeaders, LOAD_DISABLE_CACHE },
1372     { kForceFetchHeaders, LOAD_BYPASS_CACHE },
1373     { kForceValidateHeaders, LOAD_VALIDATE_CACHE },
1374   };
1375 
1376   bool range_found = false;
1377   bool external_validation_error = false;
1378 
1379   if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange))
1380     range_found = true;
1381 
1382   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) {
1383     if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) {
1384       effective_load_flags_ |= kSpecialHeaders[i].load_flag;
1385       break;
1386     }
1387   }
1388 
1389   // Check for conditionalization headers which may correspond with a
1390   // cache validation request.
1391   for (size_t i = 0; i < arraysize(kValidationHeaders); ++i) {
1392     const ValidationHeaderInfo& info = kValidationHeaders[i];
1393     std::string validation_value;
1394     if (request_->extra_headers.GetHeader(
1395             info.request_header_name, &validation_value)) {
1396       if (!external_validation_.values[i].empty() ||
1397           validation_value.empty())
1398         external_validation_error = true;
1399       external_validation_.values[i] = validation_value;
1400       external_validation_.initialized = true;
1401       break;
1402     }
1403   }
1404 
1405   // We don't support ranges and validation headers.
1406   if (range_found && external_validation_.initialized) {
1407     LOG(WARNING) << "Byte ranges AND validation headers found.";
1408     effective_load_flags_ |= LOAD_DISABLE_CACHE;
1409   }
1410 
1411   // If there is more than one validation header, we can't treat this request as
1412   // a cache validation, since we don't know for sure which header the server
1413   // will give us a response for (and they could be contradictory).
1414   if (external_validation_error) {
1415     LOG(WARNING) << "Multiple or malformed validation headers found.";
1416     effective_load_flags_ |= LOAD_DISABLE_CACHE;
1417   }
1418 
1419   if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) {
1420     partial_.reset(new PartialData);
1421     if (partial_->Init(request_->extra_headers)) {
1422       // We will be modifying the actual range requested to the server, so
1423       // let's remove the header here.
1424       custom_request_.reset(new HttpRequestInfo(*request_));
1425       custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange);
1426       request_ = custom_request_.get();
1427       partial_->SetHeaders(custom_request_->extra_headers);
1428     } else {
1429       // The range is invalid or we cannot handle it properly.
1430       VLOG(1) << "Invalid byte range found.";
1431       effective_load_flags_ |= LOAD_DISABLE_CACHE;
1432       partial_.reset(NULL);
1433     }
1434   }
1435 }
1436 
ShouldPassThrough()1437 bool HttpCache::Transaction::ShouldPassThrough() {
1438   // We may have a null disk_cache if there is an error we cannot recover from,
1439   // like not enough disk space, or sharing violations.
1440   if (!cache_->disk_cache_.get())
1441     return true;
1442 
1443   // When using the record/playback modes, we always use the cache
1444   // and we never pass through.
1445   if (cache_->mode() == RECORD || cache_->mode() == PLAYBACK)
1446     return false;
1447 
1448   if (effective_load_flags_ & LOAD_DISABLE_CACHE)
1449     return true;
1450 
1451   if (request_->method == "GET")
1452     return false;
1453 
1454   if (request_->method == "POST" &&
1455       request_->upload_data && request_->upload_data->identifier())
1456     return false;
1457 
1458   // TODO(darin): add support for caching HEAD responses
1459   return true;
1460 }
1461 
BeginCacheRead()1462 int HttpCache::Transaction::BeginCacheRead() {
1463   // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
1464   if (response_.headers->response_code() == 206 || partial_.get()) {
1465     NOTREACHED();
1466     return ERR_CACHE_MISS;
1467   }
1468 
1469   // We don't have the whole resource.
1470   if (truncated_)
1471     return ERR_CACHE_MISS;
1472 
1473   if (entry_->disk_entry->GetDataSize(kMetadataIndex))
1474     next_state_ = STATE_CACHE_READ_METADATA;
1475 
1476   return OK;
1477 }
1478 
BeginCacheValidation()1479 int HttpCache::Transaction::BeginCacheValidation() {
1480   DCHECK(mode_ == READ_WRITE);
1481 
1482   bool skip_validation = effective_load_flags_ & LOAD_PREFERRING_CACHE ||
1483                          !RequiresValidation();
1484 
1485   if (truncated_)
1486     skip_validation = !partial_->initial_validation();
1487 
1488   if ((partial_.get() && !partial_->IsCurrentRangeCached()) || invalid_range_)
1489     skip_validation = false;
1490 
1491   if (skip_validation) {
1492     if (partial_.get()) {
1493       // We are going to return the saved response headers to the caller, so
1494       // we may need to adjust them first.
1495       next_state_ = STATE_PARTIAL_HEADERS_RECEIVED;
1496       return OK;
1497     }
1498     cache_->ConvertWriterToReader(entry_);
1499     mode_ = READ;
1500 
1501     if (entry_ && entry_->disk_entry->GetDataSize(kMetadataIndex))
1502       next_state_ = STATE_CACHE_READ_METADATA;
1503   } else {
1504     // Make the network request conditional, to see if we may reuse our cached
1505     // response.  If we cannot do so, then we just resort to a normal fetch.
1506     // Our mode remains READ_WRITE for a conditional request.  We'll switch to
1507     // either READ or WRITE mode once we hear back from the server.
1508     if (!ConditionalizeRequest()) {
1509       DCHECK(!partial_.get());
1510       DCHECK_NE(206, response_.headers->response_code());
1511       mode_ = WRITE;
1512     }
1513     next_state_ = STATE_SEND_REQUEST;
1514   }
1515   return OK;
1516 }
1517 
BeginPartialCacheValidation()1518 int HttpCache::Transaction::BeginPartialCacheValidation() {
1519   DCHECK(mode_ == READ_WRITE);
1520 
1521   if (response_.headers->response_code() != 206 && !partial_.get() &&
1522       !truncated_)
1523     return BeginCacheValidation();
1524 
1525   bool byte_range_requested = partial_.get() != NULL;
1526   if (byte_range_requested) {
1527     next_state_ = STATE_CACHE_QUERY_DATA;
1528     return OK;
1529   }
1530   // The request is not for a range, but we have stored just ranges.
1531   partial_.reset(new PartialData());
1532   partial_->SetHeaders(request_->extra_headers);
1533   if (!custom_request_.get()) {
1534     custom_request_.reset(new HttpRequestInfo(*request_));
1535     request_ = custom_request_.get();
1536   }
1537 
1538   return ValidateEntryHeadersAndContinue(false);
1539 }
1540 
1541 // This should only be called once per request.
ValidateEntryHeadersAndContinue(bool byte_range_requested)1542 int HttpCache::Transaction::ValidateEntryHeadersAndContinue(
1543     bool byte_range_requested) {
1544   DCHECK(mode_ == READ_WRITE);
1545 
1546   if (!partial_->UpdateFromStoredHeaders(response_.headers, entry_->disk_entry,
1547                                          truncated_)) {
1548     // The stored data cannot be used. Get rid of it and restart this request.
1549     // We need to also reset the |truncated_| flag as a new entry is created.
1550     DoomPartialEntry(!byte_range_requested);
1551     mode_ = WRITE;
1552     truncated_ = false;
1553     next_state_ = STATE_INIT_ENTRY;
1554     return OK;
1555   }
1556 
1557   if (response_.headers->response_code() == 206)
1558     is_sparse_ = true;
1559 
1560   if (!partial_->IsRequestedRangeOK()) {
1561     // The stored data is fine, but the request may be invalid.
1562     invalid_range_ = true;
1563   }
1564 
1565   next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
1566   return OK;
1567 }
1568 
BeginExternallyConditionalizedRequest()1569 int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
1570   DCHECK_EQ(UPDATE, mode_);
1571   DCHECK(external_validation_.initialized);
1572 
1573   for (size_t i = 0;  i < arraysize(kValidationHeaders); i++) {
1574     if (external_validation_.values[i].empty())
1575       continue;
1576     // Retrieve either the cached response's "etag" or "last-modified" header.
1577     std::string validator;
1578     response_.headers->EnumerateHeader(
1579         NULL,
1580         kValidationHeaders[i].related_response_header_name,
1581         &validator);
1582 
1583     if (response_.headers->response_code() != 200 || truncated_ ||
1584         validator.empty() || validator != external_validation_.values[i]) {
1585       // The externally conditionalized request is not a validation request
1586       // for our existing cache entry. Proceed with caching disabled.
1587       DoneWritingToEntry(true);
1588     }
1589   }
1590 
1591   next_state_ = STATE_SEND_REQUEST;
1592   return OK;
1593 }
1594 
RestartNetworkRequest()1595 int HttpCache::Transaction::RestartNetworkRequest() {
1596   DCHECK(mode_ & WRITE || mode_ == NONE);
1597   DCHECK(network_trans_.get());
1598   DCHECK_EQ(STATE_NONE, next_state_);
1599 
1600   next_state_ = STATE_SEND_REQUEST_COMPLETE;
1601   int rv = network_trans_->RestartIgnoringLastError(&io_callback_);
1602   if (rv != ERR_IO_PENDING)
1603     return DoLoop(rv);
1604   return rv;
1605 }
1606 
RestartNetworkRequestWithCertificate(X509Certificate * client_cert)1607 int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
1608     X509Certificate* client_cert) {
1609   DCHECK(mode_ & WRITE || mode_ == NONE);
1610   DCHECK(network_trans_.get());
1611   DCHECK_EQ(STATE_NONE, next_state_);
1612 
1613   next_state_ = STATE_SEND_REQUEST_COMPLETE;
1614   int rv = network_trans_->RestartWithCertificate(client_cert, &io_callback_);
1615   if (rv != ERR_IO_PENDING)
1616     return DoLoop(rv);
1617   return rv;
1618 }
1619 
RestartNetworkRequestWithAuth(const string16 & username,const string16 & password)1620 int HttpCache::Transaction::RestartNetworkRequestWithAuth(
1621     const string16& username,
1622     const string16& password) {
1623   DCHECK(mode_ & WRITE || mode_ == NONE);
1624   DCHECK(network_trans_.get());
1625   DCHECK_EQ(STATE_NONE, next_state_);
1626 
1627   next_state_ = STATE_SEND_REQUEST_COMPLETE;
1628   int rv = network_trans_->RestartWithAuth(username, password, &io_callback_);
1629   if (rv != ERR_IO_PENDING)
1630     return DoLoop(rv);
1631   return rv;
1632 }
1633 
RequiresValidation()1634 bool HttpCache::Transaction::RequiresValidation() {
1635   // TODO(darin): need to do more work here:
1636   //  - make sure we have a matching request method
1637   //  - watch out for cached responses that depend on authentication
1638   // In playback mode, nothing requires validation.
1639   if (cache_->mode() == net::HttpCache::PLAYBACK)
1640     return false;
1641 
1642   if (effective_load_flags_ & LOAD_VALIDATE_CACHE)
1643     return true;
1644 
1645   if (response_.headers->RequiresValidation(
1646           response_.request_time, response_.response_time, Time::Now()))
1647     return true;
1648 
1649   // Since Vary header computation is fairly expensive, we save it for last.
1650   if (response_.vary_data.is_valid() &&
1651       !response_.vary_data.MatchesRequest(*request_, *response_.headers))
1652     return true;
1653 
1654   return false;
1655 }
1656 
ConditionalizeRequest()1657 bool HttpCache::Transaction::ConditionalizeRequest() {
1658   DCHECK(response_.headers);
1659 
1660   // This only makes sense for cached 200 or 206 responses.
1661   if (response_.headers->response_code() != 200 &&
1662       response_.headers->response_code() != 206)
1663     return false;
1664 
1665   // We should have handled this case before.
1666   DCHECK(response_.headers->response_code() != 206 ||
1667          response_.headers->HasStrongValidators());
1668 
1669   // Just use the first available ETag and/or Last-Modified header value.
1670   // TODO(darin): Or should we use the last?
1671 
1672   std::string etag_value;
1673   response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
1674 
1675   std::string last_modified_value;
1676   response_.headers->EnumerateHeader(NULL, "last-modified",
1677                                      &last_modified_value);
1678 
1679   if (etag_value.empty() && last_modified_value.empty())
1680     return false;
1681 
1682   if (!partial_.get()) {
1683     // Need to customize the request, so this forces us to allocate :(
1684     custom_request_.reset(new HttpRequestInfo(*request_));
1685     request_ = custom_request_.get();
1686   }
1687   DCHECK(custom_request_.get());
1688 
1689   bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() &&
1690                       !invalid_range_;
1691 
1692   if (!etag_value.empty()) {
1693     if (use_if_range) {
1694       // We don't want to switch to WRITE mode if we don't have this block of a
1695       // byte-range request because we may have other parts cached.
1696       custom_request_->extra_headers.SetHeader(
1697           HttpRequestHeaders::kIfRange, etag_value);
1698     } else {
1699       custom_request_->extra_headers.SetHeader(
1700           HttpRequestHeaders::kIfNoneMatch, etag_value);
1701     }
1702     // For byte-range requests, make sure that we use only one way to validate
1703     // the request.
1704     if (partial_.get() && !partial_->IsCurrentRangeCached())
1705       return true;
1706   }
1707 
1708   if (!last_modified_value.empty()) {
1709     if (use_if_range) {
1710       custom_request_->extra_headers.SetHeader(
1711           HttpRequestHeaders::kIfRange, last_modified_value);
1712     } else {
1713       custom_request_->extra_headers.SetHeader(
1714           HttpRequestHeaders::kIfModifiedSince, last_modified_value);
1715     }
1716   }
1717 
1718   return true;
1719 }
1720 
1721 // We just received some headers from the server. We may have asked for a range,
1722 // in which case partial_ has an object. This could be the first network request
1723 // we make to fulfill the original request, or we may be already reading (from
1724 // the net and / or the cache). If we are not expecting a certain response, we
1725 // just bypass the cache for this request (but again, maybe we are reading), and
1726 // delete partial_ (so we are not able to "fix" the headers that we return to
1727 // the user). This results in either a weird response for the caller (we don't
1728 // expect it after all), or maybe a range that was not exactly what it was asked
1729 // for.
1730 //
1731 // If the server is simply telling us that the resource has changed, we delete
1732 // the cached entry and restart the request as the caller intended (by returning
1733 // false from this method). However, we may not be able to do that at any point,
1734 // for instance if we already returned the headers to the user.
1735 //
1736 // WARNING: Whenever this code returns false, it has to make sure that the next
1737 // time it is called it will return true so that we don't keep retrying the
1738 // request.
ValidatePartialResponse(bool * partial_content)1739 bool HttpCache::Transaction::ValidatePartialResponse(bool* partial_content) {
1740   const HttpResponseHeaders* headers = new_response_->headers;
1741   int response_code = headers->response_code();
1742   bool partial_response = (response_code == 206);
1743   *partial_content = false;
1744 
1745   if (!entry_)
1746     return true;
1747 
1748   if (invalid_range_) {
1749     // We gave up trying to match this request with the stored data. If the
1750     // server is ok with the request, delete the entry, otherwise just ignore
1751     // this request
1752     DCHECK(!reading_);
1753     if (partial_response || response_code == 200) {
1754       DoomPartialEntry(true);
1755       mode_ = NONE;
1756     } else {
1757       if (response_code == 304)
1758         FailRangeRequest();
1759       IgnoreRangeRequest();
1760     }
1761     return true;
1762   }
1763 
1764   if (!partial_.get()) {
1765     // We are not expecting 206 but we may have one.
1766     if (partial_response)
1767       IgnoreRangeRequest();
1768 
1769     return true;
1770   }
1771 
1772   // TODO(rvargas): Do we need to consider other results here?.
1773   bool failure = response_code == 200 || response_code == 416;
1774 
1775   if (partial_->IsCurrentRangeCached()) {
1776     // We asked for "If-None-Match: " so a 206 means a new object.
1777     if (partial_response)
1778       failure = true;
1779 
1780     if (response_code == 304 && partial_->ResponseHeadersOK(headers))
1781       return true;
1782   } else {
1783     // We asked for "If-Range: " so a 206 means just another range.
1784     if (partial_response && partial_->ResponseHeadersOK(headers)) {
1785       *partial_content = true;
1786       return true;
1787     }
1788 
1789     // 304 is not expected here, but we'll spare the entry (unless it was
1790     // truncated).
1791     if (truncated_) {
1792       if (!reading_ && response_code == 200) {
1793         // The server is sending the whole resource, and we can save it.
1794         DCHECK(!partial_->IsLastRange());
1795         partial_.reset();
1796         truncated_ = false;
1797         return true;
1798       }
1799       failure = true;
1800     }
1801   }
1802 
1803   if (failure) {
1804     // We cannot truncate this entry, it has to be deleted.
1805     DoomPartialEntry(false);
1806     mode_ = NONE;
1807     if (!reading_ && !partial_->IsLastRange()) {
1808       // We'll attempt to issue another network request, this time without us
1809       // messing up the headers.
1810       partial_->RestoreHeaders(&custom_request_->extra_headers);
1811       partial_.reset();
1812       truncated_ = false;
1813       return false;
1814     }
1815     LOG(WARNING) << "Failed to revalidate partial entry";
1816     partial_.reset();
1817     return true;
1818   }
1819 
1820   IgnoreRangeRequest();
1821   return true;
1822 }
1823 
IgnoreRangeRequest()1824 void HttpCache::Transaction::IgnoreRangeRequest() {
1825   // We have a problem. We may or may not be reading already (in which case we
1826   // returned the headers), but we'll just pretend that this request is not
1827   // using the cache and see what happens. Most likely this is the first
1828   // response from the server (it's not changing its mind midway, right?).
1829   if (mode_ & WRITE) {
1830     DoneWritingToEntry(mode_ != WRITE);
1831   } else if (mode_ & READ && entry_) {
1832     cache_->DoneReadingFromEntry(entry_, this);
1833   }
1834 
1835   partial_.reset(NULL);
1836   entry_ = NULL;
1837   mode_ = NONE;
1838 }
1839 
FailRangeRequest()1840 void HttpCache::Transaction::FailRangeRequest() {
1841   response_ = *new_response_;
1842   partial_->FixResponseHeaders(response_.headers, false);
1843 }
1844 
ReadFromNetwork(IOBuffer * data,int data_len)1845 int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) {
1846   read_buf_ = data;
1847   io_buf_len_ = data_len;
1848   next_state_ = STATE_NETWORK_READ;
1849   return DoLoop(OK);
1850 }
1851 
ReadFromEntry(IOBuffer * data,int data_len)1852 int HttpCache::Transaction::ReadFromEntry(IOBuffer* data, int data_len) {
1853   read_buf_ = data;
1854   io_buf_len_ = data_len;
1855   next_state_ = STATE_CACHE_READ_DATA;
1856   return DoLoop(OK);
1857 }
1858 
WriteToEntry(int index,int offset,IOBuffer * data,int data_len,CompletionCallback * callback)1859 int HttpCache::Transaction::WriteToEntry(int index, int offset,
1860                                          IOBuffer* data, int data_len,
1861                                          CompletionCallback* callback) {
1862   if (!entry_)
1863     return data_len;
1864 
1865   int rv = 0;
1866   if (!partial_.get() || !data_len) {
1867     rv = entry_->disk_entry->WriteData(index, offset, data, data_len, callback,
1868                                        true);
1869   } else {
1870     rv = partial_->CacheWrite(entry_->disk_entry, data, data_len, callback);
1871   }
1872   return rv;
1873 }
1874 
WriteResponseInfoToEntry(bool truncated)1875 int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
1876   next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE;
1877   if (!entry_)
1878     return OK;
1879 
1880   // Do not cache no-store content (unless we are record mode).  Do not cache
1881   // content with cert errors either.  This is to prevent not reporting net
1882   // errors when loading a resource from the cache.  When we load a page over
1883   // HTTPS with a cert error we show an SSL blocking page.  If the user clicks
1884   // proceed we reload the resource ignoring the errors.  The loaded resource
1885   // is then cached.  If that resource is subsequently loaded from the cache,
1886   // no net error is reported (even though the cert status contains the actual
1887   // errors) and no SSL blocking page is shown.  An alternative would be to
1888   // reverse-map the cert status to a net error and replay the net error.
1889   if ((cache_->mode() != RECORD &&
1890        response_.headers->HasHeaderValue("cache-control", "no-store")) ||
1891       net::IsCertStatusError(response_.ssl_info.cert_status)) {
1892     DoneWritingToEntry(false);
1893     return OK;
1894   }
1895 
1896   // When writing headers, we normally only write the non-transient
1897   // headers; when in record mode, record everything.
1898   bool skip_transient_headers = (cache_->mode() != RECORD);
1899 
1900   if (truncated) {
1901     DCHECK_EQ(200, response_.headers->response_code());
1902   }
1903 
1904   scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer());
1905   response_.Persist(data->pickle(), skip_transient_headers, truncated);
1906   data->Done();
1907 
1908   // Balanced in DoCacheWriteResponseComplete.  We may be running from the
1909   // destructor of this object so cache_callback_ may be currently in use.
1910   write_headers_callback_->AddRef();
1911   io_buf_len_ = data->pickle()->size();
1912   return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data, io_buf_len_,
1913                                        write_headers_callback_, true);
1914 }
1915 
AppendResponseDataToEntry(IOBuffer * data,int data_len,CompletionCallback * callback)1916 int HttpCache::Transaction::AppendResponseDataToEntry(
1917     IOBuffer* data, int data_len, CompletionCallback* callback) {
1918   if (!entry_ || !data_len)
1919     return data_len;
1920 
1921   int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
1922   return WriteToEntry(kResponseContentIndex, current_size, data, data_len,
1923                       callback);
1924 }
1925 
DoneWritingToEntry(bool success)1926 void HttpCache::Transaction::DoneWritingToEntry(bool success) {
1927   if (!entry_)
1928     return;
1929 
1930   if (cache_->mode() == RECORD)
1931     DVLOG(1) << "Recorded: " << request_->method << request_->url
1932              << " status: " << response_.headers->response_code();
1933 
1934   cache_->DoneWritingToEntry(entry_, success);
1935   entry_ = NULL;
1936   mode_ = NONE;  // switch to 'pass through' mode
1937 }
1938 
DoomPartialEntry(bool delete_object)1939 void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
1940   DVLOG(2) << "DoomPartialEntry";
1941   int rv = cache_->DoomEntry(cache_key_, NULL);
1942   DCHECK_EQ(OK, rv);
1943   cache_->DoneWithEntry(entry_, this, false);
1944   entry_ = NULL;
1945   is_sparse_ = false;
1946   if (delete_object)
1947     partial_.reset(NULL);
1948 }
1949 
DoPartialNetworkReadCompleted(int result)1950 int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
1951   partial_->OnNetworkReadCompleted(result);
1952 
1953   if (result == 0) {
1954     // We need to move on to the next range.
1955     network_trans_.reset();
1956     next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
1957   }
1958   return result;
1959 }
1960 
DoPartialCacheReadCompleted(int result)1961 int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
1962   partial_->OnCacheReadCompleted(result);
1963 
1964   if (result == 0 && mode_ == READ_WRITE) {
1965     // We need to move on to the next range.
1966     next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION;
1967   }
1968   return result;
1969 }
1970 
1971 // Histogram data from the end of 2010 show the following distribution of
1972 // response headers:
1973 //
1974 //   Content-Length............... 87%
1975 //   Date......................... 98%
1976 //   Last-Modified................ 49%
1977 //   Etag......................... 19%
1978 //   Accept-Ranges: bytes......... 25%
1979 //   Accept-Ranges: none.......... 0.4%
1980 //   Strong Validator............. 50%
1981 //   Strong Validator + ranges.... 24%
1982 //   Strong Validator + CL........ 49%
1983 //
CanResume(bool has_data)1984 bool HttpCache::Transaction::CanResume(bool has_data) {
1985   // Double check that there is something worth keeping.
1986   if (has_data && !entry_->disk_entry->GetDataSize(kResponseContentIndex))
1987     return false;
1988 
1989   if (request_->method != "GET")
1990     return false;
1991 
1992   if (response_.headers->GetContentLength() <= 0 ||
1993       response_.headers->HasHeaderValue("Accept-Ranges", "none") ||
1994       !response_.headers->HasStrongValidators())
1995     return false;
1996 
1997   return true;
1998 }
1999 
OnIOComplete(int result)2000 void HttpCache::Transaction::OnIOComplete(int result) {
2001   DoLoop(result);
2002 }
2003 
2004 }  // namespace net
2005