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