1 // Copyright (c) 2012 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 <algorithm> 14 #include <string> 15 16 #include "base/bind.h" 17 #include "base/compiler_specific.h" 18 #include "base/memory/ref_counted.h" 19 #include "base/metrics/field_trial.h" 20 #include "base/metrics/histogram.h" 21 #include "base/metrics/sparse_histogram.h" 22 #include "base/rand_util.h" 23 #include "base/strings/string_number_conversions.h" 24 #include "base/strings/string_util.h" 25 #include "base/time/time.h" 26 #include "net/base/completion_callback.h" 27 #include "net/base/io_buffer.h" 28 #include "net/base/load_flags.h" 29 #include "net/base/load_timing_info.h" 30 #include "net/base/net_errors.h" 31 #include "net/base/net_log.h" 32 #include "net/base/upload_data_stream.h" 33 #include "net/cert/cert_status_flags.h" 34 #include "net/disk_cache/disk_cache.h" 35 #include "net/http/http_network_session.h" 36 #include "net/http/http_request_info.h" 37 #include "net/http/http_response_headers.h" 38 #include "net/http/http_transaction.h" 39 #include "net/http/http_transaction_delegate.h" 40 #include "net/http/http_util.h" 41 #include "net/http/partial_data.h" 42 #include "net/ssl/ssl_cert_request_info.h" 43 #include "net/ssl/ssl_config_service.h" 44 45 using base::Time; 46 using base::TimeDelta; 47 using base::TimeTicks; 48 49 namespace { 50 51 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6 52 // a "non-error response" is one with a 2xx (Successful) or 3xx 53 // (Redirection) status code. 54 bool NonErrorResponse(int status_code) { 55 int status_code_range = status_code / 100; 56 return status_code_range == 2 || status_code_range == 3; 57 } 58 59 // Error codes that will be considered indicative of a page being offline/ 60 // unreachable for LOAD_FROM_CACHE_IF_OFFLINE. 61 bool IsOfflineError(int error) { 62 return (error == net::ERR_NAME_NOT_RESOLVED || 63 error == net::ERR_INTERNET_DISCONNECTED || 64 error == net::ERR_ADDRESS_UNREACHABLE || 65 error == net::ERR_CONNECTION_TIMED_OUT); 66 } 67 68 // Enum for UMA, indicating the status (with regard to offline mode) of 69 // a particular request. 70 enum RequestOfflineStatus { 71 // A cache transaction hit in cache (data was present and not stale) 72 // and returned it. 73 OFFLINE_STATUS_FRESH_CACHE, 74 75 // A network request was required for a cache entry, and it succeeded. 76 OFFLINE_STATUS_NETWORK_SUCCEEDED, 77 78 // A network request was required for a cache entry, and it failed with 79 // a non-offline error. 80 OFFLINE_STATUS_NETWORK_FAILED, 81 82 // A network request was required for a cache entry, it failed with an 83 // offline error, and we could serve stale data if 84 // LOAD_FROM_CACHE_IF_OFFLINE was set. 85 OFFLINE_STATUS_DATA_AVAILABLE_OFFLINE, 86 87 // A network request was required for a cache entry, it failed with 88 // an offline error, and there was no servable data in cache (even 89 // stale data). 90 OFFLINE_STATUS_DATA_UNAVAILABLE_OFFLINE, 91 92 OFFLINE_STATUS_MAX_ENTRIES 93 }; 94 95 void RecordOfflineStatus(int load_flags, RequestOfflineStatus status) { 96 // Restrict to main frame to keep statistics close to 97 // "would have shown them something useful if offline mode was enabled". 98 if (load_flags & net::LOAD_MAIN_FRAME) { 99 UMA_HISTOGRAM_ENUMERATION("HttpCache.OfflineStatus", status, 100 OFFLINE_STATUS_MAX_ENTRIES); 101 } 102 } 103 104 } // namespace 105 106 namespace net { 107 108 struct HeaderNameAndValue { 109 const char* name; 110 const char* value; 111 }; 112 113 // If the request includes one of these request headers, then avoid caching 114 // to avoid getting confused. 115 static const HeaderNameAndValue kPassThroughHeaders[] = { 116 { "if-unmodified-since", NULL }, // causes unexpected 412s 117 { "if-match", NULL }, // causes unexpected 412s 118 { "if-range", NULL }, 119 { NULL, NULL } 120 }; 121 122 struct ValidationHeaderInfo { 123 const char* request_header_name; 124 const char* related_response_header_name; 125 }; 126 127 static const ValidationHeaderInfo kValidationHeaders[] = { 128 { "if-modified-since", "last-modified" }, 129 { "if-none-match", "etag" }, 130 }; 131 132 // If the request includes one of these request headers, then avoid reusing 133 // our cached copy if any. 134 static const HeaderNameAndValue kForceFetchHeaders[] = { 135 { "cache-control", "no-cache" }, 136 { "pragma", "no-cache" }, 137 { NULL, NULL } 138 }; 139 140 // If the request includes one of these request headers, then force our 141 // cached copy (if any) to be revalidated before reusing it. 142 static const HeaderNameAndValue kForceValidateHeaders[] = { 143 { "cache-control", "max-age=0" }, 144 { NULL, NULL } 145 }; 146 147 static bool HeaderMatches(const HttpRequestHeaders& headers, 148 const HeaderNameAndValue* search) { 149 for (; search->name; ++search) { 150 std::string header_value; 151 if (!headers.GetHeader(search->name, &header_value)) 152 continue; 153 154 if (!search->value) 155 return true; 156 157 HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ','); 158 while (v.GetNext()) { 159 if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value)) 160 return true; 161 } 162 } 163 return false; 164 } 165 166 //----------------------------------------------------------------------------- 167 168 HttpCache::Transaction::Transaction( 169 RequestPriority priority, 170 HttpCache* cache, 171 HttpTransactionDelegate* transaction_delegate) 172 : next_state_(STATE_NONE), 173 request_(NULL), 174 priority_(priority), 175 cache_(cache->AsWeakPtr()), 176 entry_(NULL), 177 new_entry_(NULL), 178 new_response_(NULL), 179 mode_(NONE), 180 target_state_(STATE_NONE), 181 reading_(false), 182 invalid_range_(false), 183 truncated_(false), 184 is_sparse_(false), 185 range_requested_(false), 186 handling_206_(false), 187 cache_pending_(false), 188 done_reading_(false), 189 vary_mismatch_(false), 190 couldnt_conditionalize_request_(false), 191 io_buf_len_(0), 192 read_offset_(0), 193 effective_load_flags_(0), 194 write_len_(0), 195 weak_factory_(this), 196 io_callback_(base::Bind(&Transaction::OnIOComplete, 197 weak_factory_.GetWeakPtr())), 198 transaction_pattern_(PATTERN_UNDEFINED), 199 defer_cache_sensitivity_delay_(false), 200 transaction_delegate_(transaction_delegate) { 201 COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders == 202 arraysize(kValidationHeaders), 203 Invalid_number_of_validation_headers); 204 base::StringToInt( 205 base::FieldTrialList::FindFullName("CacheSensitivityAnalysis"), 206 &sensitivity_analysis_percent_increase_); 207 } 208 209 HttpCache::Transaction::~Transaction() { 210 // We may have to issue another IO, but we should never invoke the callback_ 211 // after this point. 212 callback_.Reset(); 213 214 transaction_delegate_ = NULL; 215 cache_io_start_ = base::TimeTicks(); 216 deferred_cache_sensitivity_delay_ = base::TimeDelta(); 217 218 if (cache_.get()) { 219 if (entry_) { 220 bool cancel_request = reading_; 221 if (cancel_request) { 222 if (partial_.get()) { 223 entry_->disk_entry->CancelSparseIO(); 224 } else { 225 cancel_request &= (response_.headers->response_code() == 200); 226 } 227 } 228 229 cache_->DoneWithEntry(entry_, this, cancel_request); 230 } else if (cache_pending_) { 231 cache_->RemovePendingTransaction(this); 232 } 233 } 234 235 // Cancel any outstanding callbacks before we drop our reference to the 236 // HttpCache. This probably isn't strictly necessary, but might as well. 237 weak_factory_.InvalidateWeakPtrs(); 238 239 // We could still have a cache read or write in progress, so we just null the 240 // cache_ pointer to signal that we are dead. See DoCacheReadCompleted. 241 cache_.reset(); 242 } 243 244 int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len, 245 const CompletionCallback& callback) { 246 DCHECK(buf); 247 DCHECK_GT(buf_len, 0); 248 DCHECK(!callback.is_null()); 249 if (!cache_.get() || !entry_) 250 return ERR_UNEXPECTED; 251 252 // We don't need to track this operation for anything. 253 // It could be possible to check if there is something already written and 254 // avoid writing again (it should be the same, right?), but let's allow the 255 // caller to "update" the contents with something new. 256 return entry_->disk_entry->WriteData(kMetadataIndex, 0, buf, buf_len, 257 callback, true); 258 } 259 260 bool HttpCache::Transaction::AddTruncatedFlag() { 261 DCHECK(mode_ & WRITE || mode_ == NONE); 262 263 // Don't set the flag for sparse entries. 264 if (partial_.get() && !truncated_) 265 return true; 266 267 if (!CanResume(true)) 268 return false; 269 270 // We may have received the whole resource already. 271 if (done_reading_) 272 return true; 273 274 truncated_ = true; 275 target_state_ = STATE_NONE; 276 next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE; 277 DoLoop(OK); 278 return true; 279 } 280 281 LoadState HttpCache::Transaction::GetWriterLoadState() const { 282 if (network_trans_.get()) 283 return network_trans_->GetLoadState(); 284 if (entry_ || !request_) 285 return LOAD_STATE_IDLE; 286 return LOAD_STATE_WAITING_FOR_CACHE; 287 } 288 289 const BoundNetLog& HttpCache::Transaction::net_log() const { 290 return net_log_; 291 } 292 293 int HttpCache::Transaction::Start(const HttpRequestInfo* request, 294 const CompletionCallback& callback, 295 const BoundNetLog& net_log) { 296 DCHECK(request); 297 DCHECK(!callback.is_null()); 298 299 // Ensure that we only have one asynchronous call at a time. 300 DCHECK(callback_.is_null()); 301 DCHECK(!reading_); 302 DCHECK(!network_trans_.get()); 303 DCHECK(!entry_); 304 305 if (!cache_.get()) 306 return ERR_UNEXPECTED; 307 308 SetRequest(net_log, request); 309 310 // We have to wait until the backend is initialized so we start the SM. 311 next_state_ = STATE_GET_BACKEND; 312 int rv = DoLoop(OK); 313 314 // Setting this here allows us to check for the existence of a callback_ to 315 // determine if we are still inside Start. 316 if (rv == ERR_IO_PENDING) 317 callback_ = callback; 318 319 return rv; 320 } 321 322 int HttpCache::Transaction::RestartIgnoringLastError( 323 const CompletionCallback& callback) { 324 DCHECK(!callback.is_null()); 325 326 // Ensure that we only have one asynchronous call at a time. 327 DCHECK(callback_.is_null()); 328 329 if (!cache_.get()) 330 return ERR_UNEXPECTED; 331 332 int rv = RestartNetworkRequest(); 333 334 if (rv == ERR_IO_PENDING) 335 callback_ = callback; 336 337 return rv; 338 } 339 340 int HttpCache::Transaction::RestartWithCertificate( 341 X509Certificate* client_cert, 342 const CompletionCallback& callback) { 343 DCHECK(!callback.is_null()); 344 345 // Ensure that we only have one asynchronous call at a time. 346 DCHECK(callback_.is_null()); 347 348 if (!cache_.get()) 349 return ERR_UNEXPECTED; 350 351 int rv = RestartNetworkRequestWithCertificate(client_cert); 352 353 if (rv == ERR_IO_PENDING) 354 callback_ = callback; 355 356 return rv; 357 } 358 359 int HttpCache::Transaction::RestartWithAuth( 360 const AuthCredentials& credentials, 361 const CompletionCallback& callback) { 362 DCHECK(auth_response_.headers.get()); 363 DCHECK(!callback.is_null()); 364 365 // Ensure that we only have one asynchronous call at a time. 366 DCHECK(callback_.is_null()); 367 368 if (!cache_.get()) 369 return ERR_UNEXPECTED; 370 371 // Clear the intermediate response since we are going to start over. 372 auth_response_ = HttpResponseInfo(); 373 374 int rv = RestartNetworkRequestWithAuth(credentials); 375 376 if (rv == ERR_IO_PENDING) 377 callback_ = callback; 378 379 return rv; 380 } 381 382 bool HttpCache::Transaction::IsReadyToRestartForAuth() { 383 if (!network_trans_.get()) 384 return false; 385 return network_trans_->IsReadyToRestartForAuth(); 386 } 387 388 int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len, 389 const CompletionCallback& callback) { 390 DCHECK(buf); 391 DCHECK_GT(buf_len, 0); 392 DCHECK(!callback.is_null()); 393 394 DCHECK(callback_.is_null()); 395 396 if (!cache_.get()) 397 return ERR_UNEXPECTED; 398 399 // If we have an intermediate auth response at this point, then it means the 400 // user wishes to read the network response (the error page). If there is a 401 // previous response in the cache then we should leave it intact. 402 if (auth_response_.headers.get() && mode_ != NONE) { 403 UpdateTransactionPattern(PATTERN_NOT_COVERED); 404 DCHECK(mode_ & WRITE); 405 DoneWritingToEntry(mode_ == READ_WRITE); 406 mode_ = NONE; 407 } 408 409 reading_ = true; 410 int rv; 411 412 switch (mode_) { 413 case READ_WRITE: 414 DCHECK(partial_.get()); 415 if (!network_trans_.get()) { 416 // We are just reading from the cache, but we may be writing later. 417 rv = ReadFromEntry(buf, buf_len); 418 break; 419 } 420 case NONE: 421 case WRITE: 422 DCHECK(network_trans_.get()); 423 rv = ReadFromNetwork(buf, buf_len); 424 break; 425 case READ: 426 rv = ReadFromEntry(buf, buf_len); 427 break; 428 default: 429 NOTREACHED(); 430 rv = ERR_FAILED; 431 } 432 433 if (rv == ERR_IO_PENDING) { 434 DCHECK(callback_.is_null()); 435 callback_ = callback; 436 } 437 return rv; 438 } 439 440 void HttpCache::Transaction::StopCaching() { 441 // We really don't know where we are now. Hopefully there is no operation in 442 // progress, but nothing really prevents this method to be called after we 443 // returned ERR_IO_PENDING. We cannot attempt to truncate the entry at this 444 // point because we need the state machine for that (and even if we are really 445 // free, that would be an asynchronous operation). In other words, keep the 446 // entry how it is (it will be marked as truncated at destruction), and let 447 // the next piece of code that executes know that we are now reading directly 448 // from the net. 449 if (cache_.get() && entry_ && (mode_ & WRITE) && network_trans_.get() && 450 !is_sparse_ && !range_requested_) { 451 mode_ = NONE; 452 } 453 } 454 455 bool HttpCache::Transaction::GetFullRequestHeaders( 456 HttpRequestHeaders* headers) const { 457 if (network_trans_) 458 return network_trans_->GetFullRequestHeaders(headers); 459 460 // TODO(ttuttle): Read headers from cache. 461 return false; 462 } 463 464 void HttpCache::Transaction::DoneReading() { 465 if (cache_.get() && entry_) { 466 DCHECK(reading_); 467 DCHECK_NE(mode_, UPDATE); 468 if (mode_ & WRITE) 469 DoneWritingToEntry(true); 470 } 471 } 472 473 const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const { 474 // Null headers means we encountered an error or haven't a response yet 475 if (auth_response_.headers.get()) 476 return &auth_response_; 477 return (response_.headers.get() || response_.ssl_info.cert.get() || 478 response_.cert_request_info.get()) 479 ? &response_ 480 : NULL; 481 } 482 483 LoadState HttpCache::Transaction::GetLoadState() const { 484 LoadState state = GetWriterLoadState(); 485 if (state != LOAD_STATE_WAITING_FOR_CACHE) 486 return state; 487 488 if (cache_.get()) 489 return cache_->GetLoadStateForPendingTransaction(this); 490 491 return LOAD_STATE_IDLE; 492 } 493 494 UploadProgress HttpCache::Transaction::GetUploadProgress() const { 495 if (network_trans_.get()) 496 return network_trans_->GetUploadProgress(); 497 return final_upload_progress_; 498 } 499 500 bool HttpCache::Transaction::GetLoadTimingInfo( 501 LoadTimingInfo* load_timing_info) const { 502 if (network_trans_) 503 return network_trans_->GetLoadTimingInfo(load_timing_info); 504 505 if (old_network_trans_load_timing_) { 506 *load_timing_info = *old_network_trans_load_timing_; 507 return true; 508 } 509 510 if (first_cache_access_since_.is_null()) 511 return false; 512 513 // If the cache entry was opened, return that time. 514 load_timing_info->send_start = first_cache_access_since_; 515 // This time doesn't make much sense when reading from the cache, so just use 516 // the same time as send_start. 517 load_timing_info->send_end = first_cache_access_since_; 518 return true; 519 } 520 521 void HttpCache::Transaction::SetPriority(RequestPriority priority) { 522 priority_ = priority; 523 if (network_trans_) 524 network_trans_->SetPriority(priority_); 525 } 526 527 //----------------------------------------------------------------------------- 528 529 void HttpCache::Transaction::DoCallback(int rv) { 530 DCHECK(rv != ERR_IO_PENDING); 531 DCHECK(!callback_.is_null()); 532 533 read_buf_ = NULL; // Release the buffer before invoking the callback. 534 535 // Since Run may result in Read being called, clear callback_ up front. 536 CompletionCallback c = callback_; 537 callback_.Reset(); 538 c.Run(rv); 539 } 540 541 int HttpCache::Transaction::HandleResult(int rv) { 542 DCHECK(rv != ERR_IO_PENDING); 543 if (!callback_.is_null()) 544 DoCallback(rv); 545 546 return rv; 547 } 548 549 // A few common patterns: (Foo* means Foo -> FooComplete) 550 // 551 // Not-cached entry: 552 // Start(): 553 // GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* -> 554 // SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse -> 555 // CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* -> 556 // PartialHeadersReceived 557 // 558 // Read(): 559 // NetworkRead* -> CacheWriteData* 560 // 561 // Cached entry, no validation: 562 // Start(): 563 // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* 564 // -> BeginPartialCacheValidation() -> BeginCacheValidation() 565 // 566 // Read(): 567 // CacheReadData* 568 // 569 // Cached entry, validation (304): 570 // Start(): 571 // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* 572 // -> BeginPartialCacheValidation() -> BeginCacheValidation() -> 573 // SendRequest* -> SuccessfulSendRequest -> UpdateCachedResponse -> 574 // CacheWriteResponse* -> UpdateCachedResponseComplete -> 575 // OverwriteCachedResponse -> PartialHeadersReceived 576 // 577 // Read(): 578 // CacheReadData* 579 // 580 // Cached entry, validation and replace (200): 581 // Start(): 582 // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* 583 // -> BeginPartialCacheValidation() -> BeginCacheValidation() -> 584 // SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse -> 585 // CacheWriteResponse* -> DoTruncateCachedData* -> TruncateCachedMetadata* -> 586 // PartialHeadersReceived 587 // 588 // Read(): 589 // NetworkRead* -> CacheWriteData* 590 // 591 // Sparse entry, partially cached, byte range request: 592 // Start(): 593 // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* 594 // -> BeginPartialCacheValidation() -> CacheQueryData* -> 595 // ValidateEntryHeadersAndContinue() -> StartPartialCacheValidation -> 596 // CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* -> 597 // SuccessfulSendRequest -> UpdateCachedResponse -> CacheWriteResponse* -> 598 // UpdateCachedResponseComplete -> OverwriteCachedResponse -> 599 // PartialHeadersReceived 600 // 601 // Read() 1: 602 // NetworkRead* -> CacheWriteData* 603 // 604 // Read() 2: 605 // NetworkRead* -> CacheWriteData* -> StartPartialCacheValidation -> 606 // CompletePartialCacheValidation -> CacheReadData* -> 607 // 608 // Read() 3: 609 // CacheReadData* -> StartPartialCacheValidation -> 610 // CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* -> 611 // SuccessfulSendRequest -> UpdateCachedResponse* -> OverwriteCachedResponse 612 // -> PartialHeadersReceived -> NetworkRead* -> CacheWriteData* 613 // 614 int HttpCache::Transaction::DoLoop(int result) { 615 DCHECK(next_state_ != STATE_NONE); 616 617 int rv = result; 618 do { 619 State state = next_state_; 620 next_state_ = STATE_NONE; 621 switch (state) { 622 case STATE_GET_BACKEND: 623 DCHECK_EQ(OK, rv); 624 rv = DoGetBackend(); 625 break; 626 case STATE_GET_BACKEND_COMPLETE: 627 rv = DoGetBackendComplete(rv); 628 break; 629 case STATE_SEND_REQUEST: 630 DCHECK_EQ(OK, rv); 631 rv = DoSendRequest(); 632 break; 633 case STATE_SEND_REQUEST_COMPLETE: 634 rv = DoSendRequestComplete(rv); 635 break; 636 case STATE_SUCCESSFUL_SEND_REQUEST: 637 DCHECK_EQ(OK, rv); 638 rv = DoSuccessfulSendRequest(); 639 break; 640 case STATE_NETWORK_READ: 641 DCHECK_EQ(OK, rv); 642 rv = DoNetworkRead(); 643 break; 644 case STATE_NETWORK_READ_COMPLETE: 645 rv = DoNetworkReadComplete(rv); 646 break; 647 case STATE_INIT_ENTRY: 648 DCHECK_EQ(OK, rv); 649 rv = DoInitEntry(); 650 break; 651 case STATE_OPEN_ENTRY: 652 DCHECK_EQ(OK, rv); 653 rv = DoOpenEntry(); 654 break; 655 case STATE_OPEN_ENTRY_COMPLETE: 656 rv = DoOpenEntryComplete(rv); 657 break; 658 case STATE_CREATE_ENTRY: 659 DCHECK_EQ(OK, rv); 660 rv = DoCreateEntry(); 661 break; 662 case STATE_CREATE_ENTRY_COMPLETE: 663 rv = DoCreateEntryComplete(rv); 664 break; 665 case STATE_DOOM_ENTRY: 666 DCHECK_EQ(OK, rv); 667 rv = DoDoomEntry(); 668 break; 669 case STATE_DOOM_ENTRY_COMPLETE: 670 rv = DoDoomEntryComplete(rv); 671 break; 672 case STATE_ADD_TO_ENTRY: 673 DCHECK_EQ(OK, rv); 674 rv = DoAddToEntry(); 675 break; 676 case STATE_ADD_TO_ENTRY_COMPLETE: 677 rv = DoAddToEntryComplete(rv); 678 break; 679 case STATE_ADD_TO_ENTRY_COMPLETE_AFTER_DELAY: 680 rv = DoAddToEntryCompleteAfterDelay(rv); 681 break; 682 case STATE_START_PARTIAL_CACHE_VALIDATION: 683 DCHECK_EQ(OK, rv); 684 rv = DoStartPartialCacheValidation(); 685 break; 686 case STATE_COMPLETE_PARTIAL_CACHE_VALIDATION: 687 rv = DoCompletePartialCacheValidation(rv); 688 break; 689 case STATE_UPDATE_CACHED_RESPONSE: 690 DCHECK_EQ(OK, rv); 691 rv = DoUpdateCachedResponse(); 692 break; 693 case STATE_UPDATE_CACHED_RESPONSE_COMPLETE: 694 rv = DoUpdateCachedResponseComplete(rv); 695 break; 696 case STATE_OVERWRITE_CACHED_RESPONSE: 697 DCHECK_EQ(OK, rv); 698 rv = DoOverwriteCachedResponse(); 699 break; 700 case STATE_TRUNCATE_CACHED_DATA: 701 DCHECK_EQ(OK, rv); 702 rv = DoTruncateCachedData(); 703 break; 704 case STATE_TRUNCATE_CACHED_DATA_COMPLETE: 705 rv = DoTruncateCachedDataComplete(rv); 706 break; 707 case STATE_TRUNCATE_CACHED_METADATA: 708 DCHECK_EQ(OK, rv); 709 rv = DoTruncateCachedMetadata(); 710 break; 711 case STATE_TRUNCATE_CACHED_METADATA_COMPLETE: 712 rv = DoTruncateCachedMetadataComplete(rv); 713 break; 714 case STATE_PARTIAL_HEADERS_RECEIVED: 715 DCHECK_EQ(OK, rv); 716 rv = DoPartialHeadersReceived(); 717 break; 718 case STATE_CACHE_READ_RESPONSE: 719 DCHECK_EQ(OK, rv); 720 rv = DoCacheReadResponse(); 721 break; 722 case STATE_CACHE_READ_RESPONSE_COMPLETE: 723 rv = DoCacheReadResponseComplete(rv); 724 break; 725 case STATE_CACHE_WRITE_RESPONSE: 726 DCHECK_EQ(OK, rv); 727 rv = DoCacheWriteResponse(); 728 break; 729 case STATE_CACHE_WRITE_TRUNCATED_RESPONSE: 730 DCHECK_EQ(OK, rv); 731 rv = DoCacheWriteTruncatedResponse(); 732 break; 733 case STATE_CACHE_WRITE_RESPONSE_COMPLETE: 734 rv = DoCacheWriteResponseComplete(rv); 735 break; 736 case STATE_CACHE_READ_METADATA: 737 DCHECK_EQ(OK, rv); 738 rv = DoCacheReadMetadata(); 739 break; 740 case STATE_CACHE_READ_METADATA_COMPLETE: 741 rv = DoCacheReadMetadataComplete(rv); 742 break; 743 case STATE_CACHE_QUERY_DATA: 744 DCHECK_EQ(OK, rv); 745 rv = DoCacheQueryData(); 746 break; 747 case STATE_CACHE_QUERY_DATA_COMPLETE: 748 rv = DoCacheQueryDataComplete(rv); 749 break; 750 case STATE_CACHE_READ_DATA: 751 DCHECK_EQ(OK, rv); 752 rv = DoCacheReadData(); 753 break; 754 case STATE_CACHE_READ_DATA_COMPLETE: 755 rv = DoCacheReadDataComplete(rv); 756 break; 757 case STATE_CACHE_WRITE_DATA: 758 rv = DoCacheWriteData(rv); 759 break; 760 case STATE_CACHE_WRITE_DATA_COMPLETE: 761 rv = DoCacheWriteDataComplete(rv); 762 break; 763 default: 764 NOTREACHED() << "bad state"; 765 rv = ERR_FAILED; 766 break; 767 } 768 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 769 770 if (rv != ERR_IO_PENDING) 771 HandleResult(rv); 772 773 return rv; 774 } 775 776 int HttpCache::Transaction::DoGetBackend() { 777 cache_pending_ = true; 778 next_state_ = STATE_GET_BACKEND_COMPLETE; 779 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_GET_BACKEND); 780 ReportCacheActionStart(); 781 return cache_->GetBackendForTransaction(this); 782 } 783 784 int HttpCache::Transaction::DoGetBackendComplete(int result) { 785 DCHECK(result == OK || result == ERR_FAILED); 786 ReportCacheActionFinish(); 787 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_GET_BACKEND, 788 result); 789 cache_pending_ = false; 790 791 if (!ShouldPassThrough()) { 792 cache_key_ = cache_->GenerateCacheKey(request_); 793 794 // Requested cache access mode. 795 if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) { 796 mode_ = READ; 797 } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) { 798 mode_ = WRITE; 799 } else { 800 mode_ = READ_WRITE; 801 } 802 803 // Downgrade to UPDATE if the request has been externally conditionalized. 804 if (external_validation_.initialized) { 805 if (mode_ & WRITE) { 806 // Strip off the READ_DATA bit (and maybe add back a READ_META bit 807 // in case READ was off). 808 mode_ = UPDATE; 809 } else { 810 mode_ = NONE; 811 } 812 } 813 } 814 815 // Use PUT and DELETE only to invalidate existing stored entries. 816 if ((request_->method == "PUT" || request_->method == "DELETE") && 817 mode_ != READ_WRITE && mode_ != WRITE) { 818 mode_ = NONE; 819 } 820 821 // If must use cache, then we must fail. This can happen for back/forward 822 // navigations to a page generated via a form post. 823 if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE) 824 return ERR_CACHE_MISS; 825 826 if (mode_ == NONE) { 827 if (partial_.get()) { 828 partial_->RestoreHeaders(&custom_request_->extra_headers); 829 partial_.reset(); 830 } 831 next_state_ = STATE_SEND_REQUEST; 832 } else { 833 next_state_ = STATE_INIT_ENTRY; 834 } 835 836 // This is only set if we have something to do with the response. 837 range_requested_ = (partial_.get() != NULL); 838 839 return OK; 840 } 841 842 int HttpCache::Transaction::DoSendRequest() { 843 DCHECK(mode_ & WRITE || mode_ == NONE); 844 DCHECK(!network_trans_.get()); 845 846 send_request_since_ = TimeTicks::Now(); 847 848 // Create a network transaction. 849 int rv = cache_->network_layer_->CreateTransaction( 850 priority_, &network_trans_, NULL); 851 if (rv != OK) 852 return rv; 853 854 // Old load timing information, if any, is now obsolete. 855 old_network_trans_load_timing_.reset(); 856 857 ReportNetworkActionStart(); 858 next_state_ = STATE_SEND_REQUEST_COMPLETE; 859 rv = network_trans_->Start(request_, io_callback_, net_log_); 860 return rv; 861 } 862 863 int HttpCache::Transaction::DoSendRequestComplete(int result) { 864 ReportNetworkActionFinish(); 865 866 if (!cache_.get()) 867 return ERR_UNEXPECTED; 868 869 // If requested, and we have a readable cache entry, and we have 870 // an error indicating that we're offline as opposed to in contact 871 // with a bad server, read from cache anyway. 872 if (IsOfflineError(result)) { 873 if (mode_ == READ_WRITE && entry_ && !partial_) { 874 RecordOfflineStatus(effective_load_flags_, 875 OFFLINE_STATUS_DATA_AVAILABLE_OFFLINE); 876 if (effective_load_flags_ & LOAD_FROM_CACHE_IF_OFFLINE) { 877 UpdateTransactionPattern(PATTERN_NOT_COVERED); 878 response_.server_data_unavailable = true; 879 return SetupEntryForRead(); 880 } 881 } else { 882 RecordOfflineStatus(effective_load_flags_, 883 OFFLINE_STATUS_DATA_UNAVAILABLE_OFFLINE); 884 } 885 } else { 886 RecordOfflineStatus(effective_load_flags_, 887 (result == OK ? OFFLINE_STATUS_NETWORK_SUCCEEDED : 888 OFFLINE_STATUS_NETWORK_FAILED)); 889 } 890 891 // If we tried to conditionalize the request and failed, we know 892 // we won't be reading from the cache after this point. 893 if (couldnt_conditionalize_request_) 894 mode_ = WRITE; 895 896 if (result == OK) { 897 next_state_ = STATE_SUCCESSFUL_SEND_REQUEST; 898 return OK; 899 } 900 901 // Do not record requests that have network errors or restarts. 902 UpdateTransactionPattern(PATTERN_NOT_COVERED); 903 if (IsCertificateError(result)) { 904 const HttpResponseInfo* response = network_trans_->GetResponseInfo(); 905 // If we get a certificate error, then there is a certificate in ssl_info, 906 // so GetResponseInfo() should never return NULL here. 907 DCHECK(response); 908 response_.ssl_info = response->ssl_info; 909 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { 910 const HttpResponseInfo* response = network_trans_->GetResponseInfo(); 911 DCHECK(response); 912 response_.cert_request_info = response->cert_request_info; 913 } else if (response_.was_cached) { 914 DoneWritingToEntry(true); 915 } 916 return result; 917 } 918 919 // We received the response headers and there is no error. 920 int HttpCache::Transaction::DoSuccessfulSendRequest() { 921 DCHECK(!new_response_); 922 const HttpResponseInfo* new_response = network_trans_->GetResponseInfo(); 923 924 if (new_response->headers->response_code() == 401 || 925 new_response->headers->response_code() == 407) { 926 auth_response_ = *new_response; 927 return OK; 928 } 929 930 new_response_ = new_response; 931 if (!ValidatePartialResponse() && !auth_response_.headers.get()) { 932 // Something went wrong with this request and we have to restart it. 933 // If we have an authentication response, we are exposed to weird things 934 // hapenning if the user cancels the authentication before we receive 935 // the new response. 936 UpdateTransactionPattern(PATTERN_NOT_COVERED); 937 response_ = HttpResponseInfo(); 938 ResetNetworkTransaction(); 939 new_response_ = NULL; 940 next_state_ = STATE_SEND_REQUEST; 941 return OK; 942 } 943 if (handling_206_ && mode_ == READ_WRITE && !truncated_ && !is_sparse_) { 944 // We have stored the full entry, but it changed and the server is 945 // sending a range. We have to delete the old entry. 946 UpdateTransactionPattern(PATTERN_NOT_COVERED); 947 DoneWritingToEntry(false); 948 } 949 if (new_response_->headers->response_code() == 416 && 950 (request_->method == "GET" || request_->method == "POST")) { 951 DCHECK_EQ(NONE, mode_); 952 response_ = *new_response_; 953 return OK; 954 } 955 956 if (mode_ == WRITE && 957 transaction_pattern_ != PATTERN_ENTRY_CANT_CONDITIONALIZE) { 958 UpdateTransactionPattern(PATTERN_ENTRY_NOT_CACHED); 959 } 960 961 if (mode_ == WRITE && 962 (request_->method == "PUT" || request_->method == "DELETE")) { 963 if (NonErrorResponse(new_response->headers->response_code())) { 964 int ret = cache_->DoomEntry(cache_key_, NULL); 965 DCHECK_EQ(OK, ret); 966 } 967 cache_->DoneWritingToEntry(entry_, true); 968 entry_ = NULL; 969 mode_ = NONE; 970 } 971 972 if (mode_ != NONE && request_->method == "POST" && 973 NonErrorResponse(new_response->headers->response_code())) { 974 cache_->DoomMainEntryForUrl(request_->url); 975 } 976 977 // Are we expecting a response to a conditional query? 978 if (mode_ == READ_WRITE || mode_ == UPDATE) { 979 if (new_response->headers->response_code() == 304 || handling_206_) { 980 UpdateTransactionPattern(PATTERN_ENTRY_VALIDATED); 981 next_state_ = STATE_UPDATE_CACHED_RESPONSE; 982 return OK; 983 } 984 UpdateTransactionPattern(PATTERN_ENTRY_UPDATED); 985 mode_ = WRITE; 986 } 987 988 next_state_ = STATE_OVERWRITE_CACHED_RESPONSE; 989 return OK; 990 } 991 992 int HttpCache::Transaction::DoNetworkRead() { 993 ReportNetworkActionStart(); 994 next_state_ = STATE_NETWORK_READ_COMPLETE; 995 return network_trans_->Read(read_buf_.get(), io_buf_len_, io_callback_); 996 } 997 998 int HttpCache::Transaction::DoNetworkReadComplete(int result) { 999 DCHECK(mode_ & WRITE || mode_ == NONE); 1000 1001 ReportNetworkActionFinish(); 1002 1003 if (!cache_.get()) 1004 return ERR_UNEXPECTED; 1005 1006 // If there is an error or we aren't saving the data, we are done; just wait 1007 // until the destructor runs to see if we can keep the data. 1008 if (mode_ == NONE || result < 0) 1009 return result; 1010 1011 next_state_ = STATE_CACHE_WRITE_DATA; 1012 return result; 1013 } 1014 1015 int HttpCache::Transaction::DoInitEntry() { 1016 DCHECK(!new_entry_); 1017 1018 if (!cache_.get()) 1019 return ERR_UNEXPECTED; 1020 1021 if (mode_ == WRITE) { 1022 next_state_ = STATE_DOOM_ENTRY; 1023 return OK; 1024 } 1025 1026 next_state_ = STATE_OPEN_ENTRY; 1027 return OK; 1028 } 1029 1030 int HttpCache::Transaction::DoOpenEntry() { 1031 DCHECK(!new_entry_); 1032 next_state_ = STATE_OPEN_ENTRY_COMPLETE; 1033 cache_pending_ = true; 1034 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY); 1035 first_cache_access_since_ = TimeTicks::Now(); 1036 ReportCacheActionStart(); 1037 defer_cache_sensitivity_delay_ = true; 1038 return ResetCacheIOStart(cache_->OpenEntry(cache_key_, &new_entry_, this)); 1039 } 1040 1041 int HttpCache::Transaction::DoOpenEntryComplete(int result) { 1042 // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is 1043 // OK, otherwise the cache will end up with an active entry without any 1044 // transaction attached. 1045 ReportCacheActionFinish(); 1046 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result); 1047 cache_pending_ = false; 1048 if (result == OK) { 1049 next_state_ = STATE_ADD_TO_ENTRY; 1050 return OK; 1051 } 1052 1053 if (result == ERR_CACHE_RACE) { 1054 next_state_ = STATE_INIT_ENTRY; 1055 return OK; 1056 } 1057 1058 if (request_->method == "PUT" || request_->method == "DELETE") { 1059 DCHECK(mode_ == READ_WRITE || mode_ == WRITE); 1060 mode_ = NONE; 1061 next_state_ = STATE_SEND_REQUEST; 1062 return OK; 1063 } 1064 1065 if (mode_ == READ_WRITE) { 1066 mode_ = WRITE; 1067 next_state_ = STATE_CREATE_ENTRY; 1068 return OK; 1069 } 1070 if (mode_ == UPDATE) { 1071 // There is no cache entry to update; proceed without caching. 1072 mode_ = NONE; 1073 next_state_ = STATE_SEND_REQUEST; 1074 return OK; 1075 } 1076 if (cache_->mode() == PLAYBACK) 1077 DVLOG(1) << "Playback Cache Miss: " << request_->url; 1078 1079 // The entry does not exist, and we are not permitted to create a new entry, 1080 // so we must fail. 1081 return ERR_CACHE_MISS; 1082 } 1083 1084 int HttpCache::Transaction::DoCreateEntry() { 1085 DCHECK(!new_entry_); 1086 next_state_ = STATE_CREATE_ENTRY_COMPLETE; 1087 cache_pending_ = true; 1088 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY); 1089 ReportCacheActionStart(); 1090 defer_cache_sensitivity_delay_ = true; 1091 return ResetCacheIOStart(cache_->CreateEntry(cache_key_, &new_entry_, this)); 1092 } 1093 1094 int HttpCache::Transaction::DoCreateEntryComplete(int result) { 1095 // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is 1096 // OK, otherwise the cache will end up with an active entry without any 1097 // transaction attached. 1098 ReportCacheActionFinish(); 1099 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY, 1100 result); 1101 cache_pending_ = false; 1102 next_state_ = STATE_ADD_TO_ENTRY; 1103 1104 if (result == ERR_CACHE_RACE) { 1105 next_state_ = STATE_INIT_ENTRY; 1106 return OK; 1107 } 1108 1109 if (result == OK) { 1110 UMA_HISTOGRAM_BOOLEAN("HttpCache.OpenToCreateRace", false); 1111 } else { 1112 UMA_HISTOGRAM_BOOLEAN("HttpCache.OpenToCreateRace", true); 1113 // We have a race here: Maybe we failed to open the entry and decided to 1114 // create one, but by the time we called create, another transaction already 1115 // created the entry. If we want to eliminate this issue, we need an atomic 1116 // OpenOrCreate() method exposed by the disk cache. 1117 DLOG(WARNING) << "Unable to create cache entry"; 1118 mode_ = NONE; 1119 if (partial_.get()) 1120 partial_->RestoreHeaders(&custom_request_->extra_headers); 1121 next_state_ = STATE_SEND_REQUEST; 1122 } 1123 return OK; 1124 } 1125 1126 int HttpCache::Transaction::DoDoomEntry() { 1127 next_state_ = STATE_DOOM_ENTRY_COMPLETE; 1128 cache_pending_ = true; 1129 if (first_cache_access_since_.is_null()) 1130 first_cache_access_since_ = TimeTicks::Now(); 1131 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY); 1132 ReportCacheActionStart(); 1133 return ResetCacheIOStart(cache_->DoomEntry(cache_key_, this)); 1134 } 1135 1136 int HttpCache::Transaction::DoDoomEntryComplete(int result) { 1137 ReportCacheActionFinish(); 1138 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result); 1139 next_state_ = STATE_CREATE_ENTRY; 1140 cache_pending_ = false; 1141 if (result == ERR_CACHE_RACE) 1142 next_state_ = STATE_INIT_ENTRY; 1143 return OK; 1144 } 1145 1146 int HttpCache::Transaction::DoAddToEntry() { 1147 DCHECK(new_entry_); 1148 cache_pending_ = true; 1149 next_state_ = STATE_ADD_TO_ENTRY_COMPLETE; 1150 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY); 1151 DCHECK(entry_lock_waiting_since_.is_null()); 1152 entry_lock_waiting_since_ = TimeTicks::Now(); 1153 return cache_->AddTransactionToEntry(new_entry_, this); 1154 } 1155 1156 int HttpCache::Transaction::DoAddToEntryComplete(int result) { 1157 DCHECK(defer_cache_sensitivity_delay_); 1158 defer_cache_sensitivity_delay_ = false; 1159 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY, 1160 result); 1161 const TimeDelta entry_lock_wait = 1162 TimeTicks::Now() - entry_lock_waiting_since_; 1163 UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait); 1164 1165 entry_lock_waiting_since_ = TimeTicks(); 1166 DCHECK(new_entry_); 1167 cache_pending_ = false; 1168 1169 if (result == OK) 1170 entry_ = new_entry_; 1171 1172 // If there is a failure, the cache should have taken care of new_entry_. 1173 new_entry_ = NULL; 1174 1175 next_state_ = STATE_ADD_TO_ENTRY_COMPLETE_AFTER_DELAY; 1176 1177 if (deferred_cache_sensitivity_delay_ == base::TimeDelta()) 1178 return result; 1179 1180 base::TimeDelta delay = deferred_cache_sensitivity_delay_; 1181 deferred_cache_sensitivity_delay_ = base::TimeDelta(); 1182 ScheduleDelayedLoop(delay, result); 1183 return ERR_IO_PENDING; 1184 } 1185 1186 int HttpCache::Transaction::DoAddToEntryCompleteAfterDelay(int result) { 1187 if (result == ERR_CACHE_RACE) { 1188 next_state_ = STATE_INIT_ENTRY; 1189 return OK; 1190 } 1191 1192 if (result != OK) { 1193 NOTREACHED(); 1194 return result; 1195 } 1196 1197 if (mode_ == WRITE) { 1198 if (partial_.get()) 1199 partial_->RestoreHeaders(&custom_request_->extra_headers); 1200 next_state_ = STATE_SEND_REQUEST; 1201 } else { 1202 // We have to read the headers from the cached entry. 1203 DCHECK(mode_ & READ_META); 1204 next_state_ = STATE_CACHE_READ_RESPONSE; 1205 } 1206 return OK; 1207 } 1208 1209 // We may end up here multiple times for a given request. 1210 int HttpCache::Transaction::DoStartPartialCacheValidation() { 1211 if (mode_ == NONE) 1212 return OK; 1213 1214 next_state_ = STATE_COMPLETE_PARTIAL_CACHE_VALIDATION; 1215 return ResetCacheIOStart( 1216 partial_->ShouldValidateCache(entry_->disk_entry, io_callback_)); 1217 } 1218 1219 int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) { 1220 if (!result) { 1221 // This is the end of the request. 1222 if (mode_ & WRITE) { 1223 DoneWritingToEntry(true); 1224 } else { 1225 cache_->DoneReadingFromEntry(entry_, this); 1226 entry_ = NULL; 1227 } 1228 return result; 1229 } 1230 1231 if (result < 0) 1232 return result; 1233 1234 partial_->PrepareCacheValidation(entry_->disk_entry, 1235 &custom_request_->extra_headers); 1236 1237 if (reading_ && partial_->IsCurrentRangeCached()) { 1238 next_state_ = STATE_CACHE_READ_DATA; 1239 return OK; 1240 } 1241 1242 return BeginCacheValidation(); 1243 } 1244 1245 // We received 304 or 206 and we want to update the cached response headers. 1246 int HttpCache::Transaction::DoUpdateCachedResponse() { 1247 next_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE; 1248 int rv = OK; 1249 // Update cached response based on headers in new_response. 1250 // TODO(wtc): should we update cached certificate (response_.ssl_info), too? 1251 response_.headers->Update(*new_response_->headers.get()); 1252 response_.response_time = new_response_->response_time; 1253 response_.request_time = new_response_->request_time; 1254 response_.network_accessed = new_response_->network_accessed; 1255 1256 if (response_.headers->HasHeaderValue("cache-control", "no-store")) { 1257 if (!entry_->doomed) { 1258 int ret = cache_->DoomEntry(cache_key_, NULL); 1259 DCHECK_EQ(OK, ret); 1260 } 1261 } else { 1262 // If we are already reading, we already updated the headers for this 1263 // request; doing it again will change Content-Length. 1264 if (!reading_) { 1265 target_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE; 1266 next_state_ = STATE_CACHE_WRITE_RESPONSE; 1267 rv = OK; 1268 } 1269 } 1270 return rv; 1271 } 1272 1273 int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) { 1274 if (mode_ == UPDATE) { 1275 DCHECK(!handling_206_); 1276 // We got a "not modified" response and already updated the corresponding 1277 // cache entry above. 1278 // 1279 // By closing the cached entry now, we make sure that the 304 rather than 1280 // the cached 200 response, is what will be returned to the user. 1281 DoneWritingToEntry(true); 1282 } else if (entry_ && !handling_206_) { 1283 DCHECK_EQ(READ_WRITE, mode_); 1284 if (!partial_.get() || partial_->IsLastRange()) { 1285 cache_->ConvertWriterToReader(entry_); 1286 mode_ = READ; 1287 } 1288 // We no longer need the network transaction, so destroy it. 1289 final_upload_progress_ = network_trans_->GetUploadProgress(); 1290 ResetNetworkTransaction(); 1291 } else if (entry_ && handling_206_ && truncated_ && 1292 partial_->initial_validation()) { 1293 // We just finished the validation of a truncated entry, and the server 1294 // is willing to resume the operation. Now we go back and start serving 1295 // the first part to the user. 1296 ResetNetworkTransaction(); 1297 new_response_ = NULL; 1298 next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION; 1299 partial_->SetRangeToStartDownload(); 1300 return OK; 1301 } 1302 next_state_ = STATE_OVERWRITE_CACHED_RESPONSE; 1303 return OK; 1304 } 1305 1306 int HttpCache::Transaction::DoOverwriteCachedResponse() { 1307 if (mode_ & READ) { 1308 next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; 1309 return OK; 1310 } 1311 1312 // We change the value of Content-Length for partial content. 1313 if (handling_206_ && partial_.get()) 1314 partial_->FixContentLength(new_response_->headers.get()); 1315 1316 response_ = *new_response_; 1317 1318 if (handling_206_ && !CanResume(false)) { 1319 // There is no point in storing this resource because it will never be used. 1320 DoneWritingToEntry(false); 1321 if (partial_.get()) 1322 partial_->FixResponseHeaders(response_.headers.get(), true); 1323 next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; 1324 return OK; 1325 } 1326 1327 target_state_ = STATE_TRUNCATE_CACHED_DATA; 1328 next_state_ = truncated_ ? STATE_CACHE_WRITE_TRUNCATED_RESPONSE : 1329 STATE_CACHE_WRITE_RESPONSE; 1330 return OK; 1331 } 1332 1333 int HttpCache::Transaction::DoTruncateCachedData() { 1334 next_state_ = STATE_TRUNCATE_CACHED_DATA_COMPLETE; 1335 if (!entry_) 1336 return OK; 1337 if (net_log_.IsLoggingAllEvents()) 1338 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA); 1339 ReportCacheActionStart(); 1340 // Truncate the stream. 1341 return ResetCacheIOStart( 1342 WriteToEntry(kResponseContentIndex, 0, NULL, 0, io_callback_)); 1343 } 1344 1345 int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) { 1346 if (entry_) { 1347 ReportCacheActionFinish(); 1348 if (net_log_.IsLoggingAllEvents()) { 1349 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA, 1350 result); 1351 } 1352 } 1353 1354 next_state_ = STATE_TRUNCATE_CACHED_METADATA; 1355 return OK; 1356 } 1357 1358 int HttpCache::Transaction::DoTruncateCachedMetadata() { 1359 next_state_ = STATE_TRUNCATE_CACHED_METADATA_COMPLETE; 1360 if (!entry_) 1361 return OK; 1362 1363 if (net_log_.IsLoggingAllEvents()) 1364 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); 1365 ReportCacheActionStart(); 1366 return ResetCacheIOStart( 1367 WriteToEntry(kMetadataIndex, 0, NULL, 0, io_callback_)); 1368 } 1369 1370 int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) { 1371 if (entry_) { 1372 ReportCacheActionFinish(); 1373 if (net_log_.IsLoggingAllEvents()) { 1374 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, 1375 result); 1376 } 1377 } 1378 1379 // If this response is a redirect, then we can stop writing now. (We don't 1380 // need to cache the response body of a redirect.) 1381 if (response_.headers->IsRedirect(NULL)) 1382 DoneWritingToEntry(true); 1383 next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; 1384 return OK; 1385 } 1386 1387 int HttpCache::Transaction::DoPartialHeadersReceived() { 1388 new_response_ = NULL; 1389 if (entry_ && !partial_.get() && 1390 entry_->disk_entry->GetDataSize(kMetadataIndex)) 1391 next_state_ = STATE_CACHE_READ_METADATA; 1392 1393 if (!partial_.get()) 1394 return OK; 1395 1396 if (reading_) { 1397 if (network_trans_.get()) { 1398 next_state_ = STATE_NETWORK_READ; 1399 } else { 1400 next_state_ = STATE_CACHE_READ_DATA; 1401 } 1402 } else if (mode_ != NONE) { 1403 // We are about to return the headers for a byte-range request to the user, 1404 // so let's fix them. 1405 partial_->FixResponseHeaders(response_.headers.get(), true); 1406 } 1407 return OK; 1408 } 1409 1410 int HttpCache::Transaction::DoCacheReadResponse() { 1411 DCHECK(entry_); 1412 next_state_ = STATE_CACHE_READ_RESPONSE_COMPLETE; 1413 1414 io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex); 1415 read_buf_ = new IOBuffer(io_buf_len_); 1416 1417 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO); 1418 ReportCacheActionStart(); 1419 return ResetCacheIOStart(entry_->disk_entry->ReadData( 1420 kResponseInfoIndex, 0, read_buf_.get(), io_buf_len_, io_callback_)); 1421 } 1422 1423 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { 1424 ReportCacheActionFinish(); 1425 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); 1426 if (result != io_buf_len_ || 1427 !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, 1428 &response_, &truncated_)) { 1429 return OnCacheReadError(result, true); 1430 } 1431 1432 // Some resources may have slipped in as truncated when they're not. 1433 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); 1434 if (response_.headers->GetContentLength() == current_size) 1435 truncated_ = false; 1436 1437 // We now have access to the cache entry. 1438 // 1439 // o if we are a reader for the transaction, then we can start reading the 1440 // cache entry. 1441 // 1442 // o if we can read or write, then we should check if the cache entry needs 1443 // to be validated and then issue a network request if needed or just read 1444 // from the cache if the cache entry is already valid. 1445 // 1446 // o if we are set to UPDATE, then we are handling an externally 1447 // conditionalized request (if-modified-since / if-none-match). We check 1448 // if the request headers define a validation request. 1449 // 1450 switch (mode_) { 1451 case READ: 1452 UpdateTransactionPattern(PATTERN_ENTRY_USED); 1453 result = BeginCacheRead(); 1454 break; 1455 case READ_WRITE: 1456 result = BeginPartialCacheValidation(); 1457 break; 1458 case UPDATE: 1459 result = BeginExternallyConditionalizedRequest(); 1460 break; 1461 case WRITE: 1462 default: 1463 NOTREACHED(); 1464 result = ERR_FAILED; 1465 } 1466 return result; 1467 } 1468 1469 int HttpCache::Transaction::DoCacheWriteResponse() { 1470 if (entry_) { 1471 if (net_log_.IsLoggingAllEvents()) 1472 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); 1473 ReportCacheActionStart(); 1474 } 1475 return WriteResponseInfoToEntry(false); 1476 } 1477 1478 int HttpCache::Transaction::DoCacheWriteTruncatedResponse() { 1479 if (entry_) { 1480 if (net_log_.IsLoggingAllEvents()) 1481 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); 1482 ReportCacheActionStart(); 1483 } 1484 return WriteResponseInfoToEntry(true); 1485 } 1486 1487 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) { 1488 next_state_ = target_state_; 1489 target_state_ = STATE_NONE; 1490 if (!entry_) 1491 return OK; 1492 ReportCacheActionFinish(); 1493 if (net_log_.IsLoggingAllEvents()) { 1494 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO, 1495 result); 1496 } 1497 1498 // Balance the AddRef from WriteResponseInfoToEntry. 1499 if (result != io_buf_len_) { 1500 DLOG(ERROR) << "failed to write response info to cache"; 1501 DoneWritingToEntry(false); 1502 } 1503 return OK; 1504 } 1505 1506 int HttpCache::Transaction::DoCacheReadMetadata() { 1507 DCHECK(entry_); 1508 DCHECK(!response_.metadata.get()); 1509 next_state_ = STATE_CACHE_READ_METADATA_COMPLETE; 1510 1511 response_.metadata = 1512 new IOBufferWithSize(entry_->disk_entry->GetDataSize(kMetadataIndex)); 1513 1514 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO); 1515 ReportCacheActionStart(); 1516 return ResetCacheIOStart( 1517 entry_->disk_entry->ReadData(kMetadataIndex, 1518 0, 1519 response_.metadata.get(), 1520 response_.metadata->size(), 1521 io_callback_)); 1522 } 1523 1524 int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) { 1525 ReportCacheActionFinish(); 1526 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); 1527 if (result != response_.metadata->size()) 1528 return OnCacheReadError(result, false); 1529 return OK; 1530 } 1531 1532 int HttpCache::Transaction::DoCacheQueryData() { 1533 next_state_ = STATE_CACHE_QUERY_DATA_COMPLETE; 1534 1535 // Balanced in DoCacheQueryDataComplete. 1536 return ResetCacheIOStart( 1537 entry_->disk_entry->ReadyForSparseIO(io_callback_)); 1538 } 1539 1540 int HttpCache::Transaction::DoCacheQueryDataComplete(int result) { 1541 #if defined(OS_ANDROID) 1542 if (result == ERR_NOT_IMPLEMENTED) { 1543 // Restart the request overwriting the cache entry. 1544 // 1545 // Note: this would have fixed range requests for debug builds on all OSes, 1546 // not just Android, but karen@ prefers to limit the effect based on OS for 1547 // cherry-picked fixes. 1548 // TODO(pasko): remove the OS_ANDROID limitation as soon as the fix proves 1549 // useful after the cherry-pick. 1550 // TODO(pasko): remove this workaround as soon as the SimpleBackendImpl 1551 // supports Sparse IO. 1552 return DoRestartPartialRequest(); 1553 } 1554 #endif 1555 DCHECK_EQ(OK, result); 1556 if (!cache_.get()) 1557 return ERR_UNEXPECTED; 1558 1559 return ValidateEntryHeadersAndContinue(); 1560 } 1561 1562 int HttpCache::Transaction::DoCacheReadData() { 1563 DCHECK(entry_); 1564 next_state_ = STATE_CACHE_READ_DATA_COMPLETE; 1565 1566 if (net_log_.IsLoggingAllEvents()) 1567 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA); 1568 ReportCacheActionStart(); 1569 if (partial_.get()) { 1570 return ResetCacheIOStart(partial_->CacheRead( 1571 entry_->disk_entry, read_buf_.get(), io_buf_len_, io_callback_)); 1572 } 1573 1574 return ResetCacheIOStart(entry_->disk_entry->ReadData(kResponseContentIndex, 1575 read_offset_, 1576 read_buf_.get(), 1577 io_buf_len_, 1578 io_callback_)); 1579 } 1580 1581 int HttpCache::Transaction::DoCacheReadDataComplete(int result) { 1582 ReportCacheActionFinish(); 1583 if (net_log_.IsLoggingAllEvents()) { 1584 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_DATA, 1585 result); 1586 } 1587 1588 if (!cache_.get()) 1589 return ERR_UNEXPECTED; 1590 1591 if (partial_.get()) { 1592 // Partial requests are confusing to report in histograms because they may 1593 // have multiple underlying requests. 1594 UpdateTransactionPattern(PATTERN_NOT_COVERED); 1595 return DoPartialCacheReadCompleted(result); 1596 } 1597 1598 if (result > 0) { 1599 read_offset_ += result; 1600 } else if (result == 0) { // End of file. 1601 RecordHistograms(); 1602 cache_->DoneReadingFromEntry(entry_, this); 1603 entry_ = NULL; 1604 } else { 1605 return OnCacheReadError(result, false); 1606 } 1607 return result; 1608 } 1609 1610 int HttpCache::Transaction::DoCacheWriteData(int num_bytes) { 1611 next_state_ = STATE_CACHE_WRITE_DATA_COMPLETE; 1612 write_len_ = num_bytes; 1613 if (entry_) { 1614 if (net_log_.IsLoggingAllEvents()) 1615 net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA); 1616 ReportCacheActionStart(); 1617 } 1618 1619 return ResetCacheIOStart( 1620 AppendResponseDataToEntry(read_buf_.get(), num_bytes, io_callback_)); 1621 } 1622 1623 int HttpCache::Transaction::DoCacheWriteDataComplete(int result) { 1624 if (entry_) { 1625 ReportCacheActionFinish(); 1626 if (net_log_.IsLoggingAllEvents()) { 1627 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA, 1628 result); 1629 } 1630 } 1631 // Balance the AddRef from DoCacheWriteData. 1632 if (!cache_.get()) 1633 return ERR_UNEXPECTED; 1634 1635 if (result != write_len_) { 1636 DLOG(ERROR) << "failed to write response data to cache"; 1637 DoneWritingToEntry(false); 1638 1639 // We want to ignore errors writing to disk and just keep reading from 1640 // the network. 1641 result = write_len_; 1642 } else if (!done_reading_ && entry_) { 1643 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); 1644 int64 body_size = response_.headers->GetContentLength(); 1645 if (body_size >= 0 && body_size <= current_size) 1646 done_reading_ = true; 1647 } 1648 1649 if (partial_.get()) { 1650 // This may be the last request. 1651 if (!(result == 0 && !truncated_ && 1652 (partial_->IsLastRange() || mode_ == WRITE))) 1653 return DoPartialNetworkReadCompleted(result); 1654 } 1655 1656 if (result == 0) { 1657 // End of file. This may be the result of a connection problem so see if we 1658 // have to keep the entry around to be flagged as truncated later on. 1659 if (done_reading_ || !entry_ || partial_.get() || 1660 response_.headers->GetContentLength() <= 0) 1661 DoneWritingToEntry(true); 1662 } 1663 1664 return result; 1665 } 1666 1667 //----------------------------------------------------------------------------- 1668 1669 void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, 1670 const HttpRequestInfo* request) { 1671 net_log_ = net_log; 1672 request_ = request; 1673 effective_load_flags_ = request_->load_flags; 1674 1675 switch (cache_->mode()) { 1676 case NORMAL: 1677 break; 1678 case RECORD: 1679 // When in record mode, we want to NEVER load from the cache. 1680 // The reason for this is beacuse we save the Set-Cookie headers 1681 // (intentionally). If we read from the cache, we replay them 1682 // prematurely. 1683 effective_load_flags_ |= LOAD_BYPASS_CACHE; 1684 break; 1685 case PLAYBACK: 1686 // When in playback mode, we want to load exclusively from the cache. 1687 effective_load_flags_ |= LOAD_ONLY_FROM_CACHE; 1688 break; 1689 case DISABLE: 1690 effective_load_flags_ |= LOAD_DISABLE_CACHE; 1691 break; 1692 } 1693 1694 // Some headers imply load flags. The order here is significant. 1695 // 1696 // LOAD_DISABLE_CACHE : no cache read or write 1697 // LOAD_BYPASS_CACHE : no cache read 1698 // LOAD_VALIDATE_CACHE : no cache read unless validation 1699 // 1700 // The former modes trump latter modes, so if we find a matching header we 1701 // can stop iterating kSpecialHeaders. 1702 // 1703 static const struct { 1704 const HeaderNameAndValue* search; 1705 int load_flag; 1706 } kSpecialHeaders[] = { 1707 { kPassThroughHeaders, LOAD_DISABLE_CACHE }, 1708 { kForceFetchHeaders, LOAD_BYPASS_CACHE }, 1709 { kForceValidateHeaders, LOAD_VALIDATE_CACHE }, 1710 }; 1711 1712 bool range_found = false; 1713 bool external_validation_error = false; 1714 1715 if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange)) 1716 range_found = true; 1717 1718 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) { 1719 if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) { 1720 effective_load_flags_ |= kSpecialHeaders[i].load_flag; 1721 break; 1722 } 1723 } 1724 1725 // Check for conditionalization headers which may correspond with a 1726 // cache validation request. 1727 for (size_t i = 0; i < arraysize(kValidationHeaders); ++i) { 1728 const ValidationHeaderInfo& info = kValidationHeaders[i]; 1729 std::string validation_value; 1730 if (request_->extra_headers.GetHeader( 1731 info.request_header_name, &validation_value)) { 1732 if (!external_validation_.values[i].empty() || 1733 validation_value.empty()) { 1734 external_validation_error = true; 1735 } 1736 external_validation_.values[i] = validation_value; 1737 external_validation_.initialized = true; 1738 } 1739 } 1740 1741 // We don't support ranges and validation headers. 1742 if (range_found && external_validation_.initialized) { 1743 LOG(WARNING) << "Byte ranges AND validation headers found."; 1744 effective_load_flags_ |= LOAD_DISABLE_CACHE; 1745 } 1746 1747 // If there is more than one validation header, we can't treat this request as 1748 // a cache validation, since we don't know for sure which header the server 1749 // will give us a response for (and they could be contradictory). 1750 if (external_validation_error) { 1751 LOG(WARNING) << "Multiple or malformed validation headers found."; 1752 effective_load_flags_ |= LOAD_DISABLE_CACHE; 1753 } 1754 1755 if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) { 1756 UpdateTransactionPattern(PATTERN_NOT_COVERED); 1757 partial_.reset(new PartialData); 1758 if (request_->method == "GET" && partial_->Init(request_->extra_headers)) { 1759 // We will be modifying the actual range requested to the server, so 1760 // let's remove the header here. 1761 custom_request_.reset(new HttpRequestInfo(*request_)); 1762 custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange); 1763 request_ = custom_request_.get(); 1764 partial_->SetHeaders(custom_request_->extra_headers); 1765 } else { 1766 // The range is invalid or we cannot handle it properly. 1767 VLOG(1) << "Invalid byte range found."; 1768 effective_load_flags_ |= LOAD_DISABLE_CACHE; 1769 partial_.reset(NULL); 1770 } 1771 } 1772 } 1773 1774 bool HttpCache::Transaction::ShouldPassThrough() { 1775 // We may have a null disk_cache if there is an error we cannot recover from, 1776 // like not enough disk space, or sharing violations. 1777 if (!cache_->disk_cache_.get()) 1778 return true; 1779 1780 // When using the record/playback modes, we always use the cache 1781 // and we never pass through. 1782 if (cache_->mode() == RECORD || cache_->mode() == PLAYBACK) 1783 return false; 1784 1785 if (effective_load_flags_ & LOAD_DISABLE_CACHE) 1786 return true; 1787 1788 if (request_->method == "GET") 1789 return false; 1790 1791 if (request_->method == "POST" && request_->upload_data_stream && 1792 request_->upload_data_stream->identifier()) { 1793 return false; 1794 } 1795 1796 if (request_->method == "PUT" && request_->upload_data_stream) 1797 return false; 1798 1799 if (request_->method == "DELETE") 1800 return false; 1801 1802 // TODO(darin): add support for caching HEAD responses 1803 return true; 1804 } 1805 1806 int HttpCache::Transaction::BeginCacheRead() { 1807 // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges. 1808 if (response_.headers->response_code() == 206 || partial_.get()) { 1809 NOTREACHED(); 1810 return ERR_CACHE_MISS; 1811 } 1812 1813 // We don't have the whole resource. 1814 if (truncated_) 1815 return ERR_CACHE_MISS; 1816 1817 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) 1818 next_state_ = STATE_CACHE_READ_METADATA; 1819 1820 return OK; 1821 } 1822 1823 int HttpCache::Transaction::BeginCacheValidation() { 1824 DCHECK(mode_ == READ_WRITE); 1825 1826 bool skip_validation = !RequiresValidation(); 1827 1828 if (truncated_) { 1829 // Truncated entries can cause partial gets, so we shouldn't record this 1830 // load in histograms. 1831 UpdateTransactionPattern(PATTERN_NOT_COVERED); 1832 skip_validation = !partial_->initial_validation(); 1833 } 1834 1835 if (partial_.get() && (is_sparse_ || truncated_) && 1836 (!partial_->IsCurrentRangeCached() || invalid_range_)) { 1837 // Force revalidation for sparse or truncated entries. Note that we don't 1838 // want to ignore the regular validation logic just because a byte range was 1839 // part of the request. 1840 skip_validation = false; 1841 } 1842 1843 if (skip_validation) { 1844 UpdateTransactionPattern(PATTERN_ENTRY_USED); 1845 RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE); 1846 return SetupEntryForRead(); 1847 } else { 1848 // Make the network request conditional, to see if we may reuse our cached 1849 // response. If we cannot do so, then we just resort to a normal fetch. 1850 // Our mode remains READ_WRITE for a conditional request. Even if the 1851 // conditionalization fails, we don't switch to WRITE mode until we 1852 // know we won't be falling back to using the cache entry in the 1853 // LOAD_FROM_CACHE_IF_OFFLINE case. 1854 if (!ConditionalizeRequest()) { 1855 couldnt_conditionalize_request_ = true; 1856 UpdateTransactionPattern(PATTERN_ENTRY_CANT_CONDITIONALIZE); 1857 if (partial_.get()) 1858 return DoRestartPartialRequest(); 1859 1860 DCHECK_NE(206, response_.headers->response_code()); 1861 } 1862 next_state_ = STATE_SEND_REQUEST; 1863 } 1864 return OK; 1865 } 1866 1867 int HttpCache::Transaction::BeginPartialCacheValidation() { 1868 DCHECK(mode_ == READ_WRITE); 1869 1870 if (response_.headers->response_code() != 206 && !partial_.get() && 1871 !truncated_) { 1872 return BeginCacheValidation(); 1873 } 1874 1875 // Partial requests should not be recorded in histograms. 1876 UpdateTransactionPattern(PATTERN_NOT_COVERED); 1877 if (range_requested_) { 1878 next_state_ = STATE_CACHE_QUERY_DATA; 1879 return OK; 1880 } 1881 // The request is not for a range, but we have stored just ranges. 1882 partial_.reset(new PartialData()); 1883 partial_->SetHeaders(request_->extra_headers); 1884 if (!custom_request_.get()) { 1885 custom_request_.reset(new HttpRequestInfo(*request_)); 1886 request_ = custom_request_.get(); 1887 } 1888 1889 return ValidateEntryHeadersAndContinue(); 1890 } 1891 1892 // This should only be called once per request. 1893 int HttpCache::Transaction::ValidateEntryHeadersAndContinue() { 1894 DCHECK(mode_ == READ_WRITE); 1895 1896 if (!partial_->UpdateFromStoredHeaders( 1897 response_.headers.get(), entry_->disk_entry, truncated_)) { 1898 return DoRestartPartialRequest(); 1899 } 1900 1901 if (response_.headers->response_code() == 206) 1902 is_sparse_ = true; 1903 1904 if (!partial_->IsRequestedRangeOK()) { 1905 // The stored data is fine, but the request may be invalid. 1906 invalid_range_ = true; 1907 } 1908 1909 next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION; 1910 return OK; 1911 } 1912 1913 int HttpCache::Transaction::BeginExternallyConditionalizedRequest() { 1914 DCHECK_EQ(UPDATE, mode_); 1915 DCHECK(external_validation_.initialized); 1916 1917 for (size_t i = 0; i < arraysize(kValidationHeaders); i++) { 1918 if (external_validation_.values[i].empty()) 1919 continue; 1920 // Retrieve either the cached response's "etag" or "last-modified" header. 1921 std::string validator; 1922 response_.headers->EnumerateHeader( 1923 NULL, 1924 kValidationHeaders[i].related_response_header_name, 1925 &validator); 1926 1927 if (response_.headers->response_code() != 200 || truncated_ || 1928 validator.empty() || validator != external_validation_.values[i]) { 1929 // The externally conditionalized request is not a validation request 1930 // for our existing cache entry. Proceed with caching disabled. 1931 UpdateTransactionPattern(PATTERN_NOT_COVERED); 1932 DoneWritingToEntry(true); 1933 } 1934 } 1935 1936 next_state_ = STATE_SEND_REQUEST; 1937 return OK; 1938 } 1939 1940 int HttpCache::Transaction::RestartNetworkRequest() { 1941 DCHECK(mode_ & WRITE || mode_ == NONE); 1942 DCHECK(network_trans_.get()); 1943 DCHECK_EQ(STATE_NONE, next_state_); 1944 1945 ReportNetworkActionStart(); 1946 next_state_ = STATE_SEND_REQUEST_COMPLETE; 1947 int rv = network_trans_->RestartIgnoringLastError(io_callback_); 1948 if (rv != ERR_IO_PENDING) 1949 return DoLoop(rv); 1950 return rv; 1951 } 1952 1953 int HttpCache::Transaction::RestartNetworkRequestWithCertificate( 1954 X509Certificate* client_cert) { 1955 DCHECK(mode_ & WRITE || mode_ == NONE); 1956 DCHECK(network_trans_.get()); 1957 DCHECK_EQ(STATE_NONE, next_state_); 1958 1959 ReportNetworkActionStart(); 1960 next_state_ = STATE_SEND_REQUEST_COMPLETE; 1961 int rv = network_trans_->RestartWithCertificate(client_cert, io_callback_); 1962 if (rv != ERR_IO_PENDING) 1963 return DoLoop(rv); 1964 return rv; 1965 } 1966 1967 int HttpCache::Transaction::RestartNetworkRequestWithAuth( 1968 const AuthCredentials& credentials) { 1969 DCHECK(mode_ & WRITE || mode_ == NONE); 1970 DCHECK(network_trans_.get()); 1971 DCHECK_EQ(STATE_NONE, next_state_); 1972 1973 ReportNetworkActionStart(); 1974 next_state_ = STATE_SEND_REQUEST_COMPLETE; 1975 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); 1976 if (rv != ERR_IO_PENDING) 1977 return DoLoop(rv); 1978 return rv; 1979 } 1980 1981 bool HttpCache::Transaction::RequiresValidation() { 1982 // TODO(darin): need to do more work here: 1983 // - make sure we have a matching request method 1984 // - watch out for cached responses that depend on authentication 1985 1986 // In playback mode, nothing requires validation. 1987 if (cache_->mode() == net::HttpCache::PLAYBACK) 1988 return false; 1989 1990 if (response_.vary_data.is_valid() && 1991 !response_.vary_data.MatchesRequest(*request_, 1992 *response_.headers.get())) { 1993 vary_mismatch_ = true; 1994 return true; 1995 } 1996 1997 if (effective_load_flags_ & LOAD_PREFERRING_CACHE) 1998 return false; 1999 2000 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) 2001 return true; 2002 2003 if (request_->method == "PUT" || request_->method == "DELETE") 2004 return true; 2005 2006 if (response_.headers->RequiresValidation( 2007 response_.request_time, response_.response_time, Time::Now())) { 2008 return true; 2009 } 2010 2011 return false; 2012 } 2013 2014 bool HttpCache::Transaction::ConditionalizeRequest() { 2015 DCHECK(response_.headers.get()); 2016 2017 if (request_->method == "PUT" || request_->method == "DELETE") 2018 return false; 2019 2020 // This only makes sense for cached 200 or 206 responses. 2021 if (response_.headers->response_code() != 200 && 2022 response_.headers->response_code() != 206) { 2023 return false; 2024 } 2025 2026 // We should have handled this case before. 2027 DCHECK(response_.headers->response_code() != 206 || 2028 response_.headers->HasStrongValidators()); 2029 2030 // Just use the first available ETag and/or Last-Modified header value. 2031 // TODO(darin): Or should we use the last? 2032 2033 std::string etag_value; 2034 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) 2035 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); 2036 2037 std::string last_modified_value; 2038 if (!vary_mismatch_) { 2039 response_.headers->EnumerateHeader(NULL, "last-modified", 2040 &last_modified_value); 2041 } 2042 2043 if (etag_value.empty() && last_modified_value.empty()) 2044 return false; 2045 2046 if (!partial_.get()) { 2047 // Need to customize the request, so this forces us to allocate :( 2048 custom_request_.reset(new HttpRequestInfo(*request_)); 2049 request_ = custom_request_.get(); 2050 } 2051 DCHECK(custom_request_.get()); 2052 2053 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && 2054 !invalid_range_; 2055 2056 if (!etag_value.empty()) { 2057 if (use_if_range) { 2058 // We don't want to switch to WRITE mode if we don't have this block of a 2059 // byte-range request because we may have other parts cached. 2060 custom_request_->extra_headers.SetHeader( 2061 HttpRequestHeaders::kIfRange, etag_value); 2062 } else { 2063 custom_request_->extra_headers.SetHeader( 2064 HttpRequestHeaders::kIfNoneMatch, etag_value); 2065 } 2066 // For byte-range requests, make sure that we use only one way to validate 2067 // the request. 2068 if (partial_.get() && !partial_->IsCurrentRangeCached()) 2069 return true; 2070 } 2071 2072 if (!last_modified_value.empty()) { 2073 if (use_if_range) { 2074 custom_request_->extra_headers.SetHeader( 2075 HttpRequestHeaders::kIfRange, last_modified_value); 2076 } else { 2077 custom_request_->extra_headers.SetHeader( 2078 HttpRequestHeaders::kIfModifiedSince, last_modified_value); 2079 } 2080 } 2081 2082 return true; 2083 } 2084 2085 // We just received some headers from the server. We may have asked for a range, 2086 // in which case partial_ has an object. This could be the first network request 2087 // we make to fulfill the original request, or we may be already reading (from 2088 // the net and / or the cache). If we are not expecting a certain response, we 2089 // just bypass the cache for this request (but again, maybe we are reading), and 2090 // delete partial_ (so we are not able to "fix" the headers that we return to 2091 // the user). This results in either a weird response for the caller (we don't 2092 // expect it after all), or maybe a range that was not exactly what it was asked 2093 // for. 2094 // 2095 // If the server is simply telling us that the resource has changed, we delete 2096 // the cached entry and restart the request as the caller intended (by returning 2097 // false from this method). However, we may not be able to do that at any point, 2098 // for instance if we already returned the headers to the user. 2099 // 2100 // WARNING: Whenever this code returns false, it has to make sure that the next 2101 // time it is called it will return true so that we don't keep retrying the 2102 // request. 2103 bool HttpCache::Transaction::ValidatePartialResponse() { 2104 const HttpResponseHeaders* headers = new_response_->headers.get(); 2105 int response_code = headers->response_code(); 2106 bool partial_response = (response_code == 206); 2107 handling_206_ = false; 2108 2109 if (!entry_ || request_->method != "GET") 2110 return true; 2111 2112 if (invalid_range_) { 2113 // We gave up trying to match this request with the stored data. If the 2114 // server is ok with the request, delete the entry, otherwise just ignore 2115 // this request 2116 DCHECK(!reading_); 2117 if (partial_response || response_code == 200) { 2118 DoomPartialEntry(true); 2119 mode_ = NONE; 2120 } else { 2121 if (response_code == 304) 2122 FailRangeRequest(); 2123 IgnoreRangeRequest(); 2124 } 2125 return true; 2126 } 2127 2128 if (!partial_.get()) { 2129 // We are not expecting 206 but we may have one. 2130 if (partial_response) 2131 IgnoreRangeRequest(); 2132 2133 return true; 2134 } 2135 2136 // TODO(rvargas): Do we need to consider other results here?. 2137 bool failure = response_code == 200 || response_code == 416; 2138 2139 if (partial_->IsCurrentRangeCached()) { 2140 // We asked for "If-None-Match: " so a 206 means a new object. 2141 if (partial_response) 2142 failure = true; 2143 2144 if (response_code == 304 && partial_->ResponseHeadersOK(headers)) 2145 return true; 2146 } else { 2147 // We asked for "If-Range: " so a 206 means just another range. 2148 if (partial_response && partial_->ResponseHeadersOK(headers)) { 2149 handling_206_ = true; 2150 return true; 2151 } 2152 2153 if (!reading_ && !is_sparse_ && !partial_response) { 2154 // See if we can ignore the fact that we issued a byte range request. 2155 // If the server sends 200, just store it. If it sends an error, redirect 2156 // or something else, we may store the response as long as we didn't have 2157 // anything already stored. 2158 if (response_code == 200 || 2159 (!truncated_ && response_code != 304 && response_code != 416)) { 2160 // The server is sending something else, and we can save it. 2161 DCHECK((truncated_ && !partial_->IsLastRange()) || range_requested_); 2162 partial_.reset(); 2163 truncated_ = false; 2164 return true; 2165 } 2166 } 2167 2168 // 304 is not expected here, but we'll spare the entry (unless it was 2169 // truncated). 2170 if (truncated_) 2171 failure = true; 2172 } 2173 2174 if (failure) { 2175 // We cannot truncate this entry, it has to be deleted. 2176 UpdateTransactionPattern(PATTERN_NOT_COVERED); 2177 DoomPartialEntry(false); 2178 mode_ = NONE; 2179 if (!reading_ && !partial_->IsLastRange()) { 2180 // We'll attempt to issue another network request, this time without us 2181 // messing up the headers. 2182 partial_->RestoreHeaders(&custom_request_->extra_headers); 2183 partial_.reset(); 2184 truncated_ = false; 2185 return false; 2186 } 2187 LOG(WARNING) << "Failed to revalidate partial entry"; 2188 partial_.reset(); 2189 return true; 2190 } 2191 2192 IgnoreRangeRequest(); 2193 return true; 2194 } 2195 2196 void HttpCache::Transaction::IgnoreRangeRequest() { 2197 // We have a problem. We may or may not be reading already (in which case we 2198 // returned the headers), but we'll just pretend that this request is not 2199 // using the cache and see what happens. Most likely this is the first 2200 // response from the server (it's not changing its mind midway, right?). 2201 UpdateTransactionPattern(PATTERN_NOT_COVERED); 2202 if (mode_ & WRITE) 2203 DoneWritingToEntry(mode_ != WRITE); 2204 else if (mode_ & READ && entry_) 2205 cache_->DoneReadingFromEntry(entry_, this); 2206 2207 partial_.reset(NULL); 2208 entry_ = NULL; 2209 mode_ = NONE; 2210 } 2211 2212 void HttpCache::Transaction::FailRangeRequest() { 2213 response_ = *new_response_; 2214 partial_->FixResponseHeaders(response_.headers.get(), false); 2215 } 2216 2217 int HttpCache::Transaction::SetupEntryForRead() { 2218 if (network_trans_) 2219 ResetNetworkTransaction(); 2220 if (partial_.get()) { 2221 if (truncated_ || is_sparse_ || !invalid_range_) { 2222 // We are going to return the saved response headers to the caller, so 2223 // we may need to adjust them first. 2224 next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; 2225 return OK; 2226 } else { 2227 partial_.reset(); 2228 } 2229 } 2230 cache_->ConvertWriterToReader(entry_); 2231 mode_ = READ; 2232 2233 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) 2234 next_state_ = STATE_CACHE_READ_METADATA; 2235 return OK; 2236 } 2237 2238 2239 int HttpCache::Transaction::ReadFromNetwork(IOBuffer* data, int data_len) { 2240 read_buf_ = data; 2241 io_buf_len_ = data_len; 2242 next_state_ = STATE_NETWORK_READ; 2243 return DoLoop(OK); 2244 } 2245 2246 int HttpCache::Transaction::ReadFromEntry(IOBuffer* data, int data_len) { 2247 read_buf_ = data; 2248 io_buf_len_ = data_len; 2249 next_state_ = STATE_CACHE_READ_DATA; 2250 return DoLoop(OK); 2251 } 2252 2253 int HttpCache::Transaction::WriteToEntry(int index, int offset, 2254 IOBuffer* data, int data_len, 2255 const CompletionCallback& callback) { 2256 if (!entry_) 2257 return data_len; 2258 2259 int rv = 0; 2260 if (!partial_.get() || !data_len) { 2261 rv = entry_->disk_entry->WriteData(index, offset, data, data_len, callback, 2262 true); 2263 } else { 2264 rv = partial_->CacheWrite(entry_->disk_entry, data, data_len, callback); 2265 } 2266 return rv; 2267 } 2268 2269 int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) { 2270 next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE; 2271 if (!entry_) 2272 return OK; 2273 2274 // Do not cache no-store content (unless we are record mode). Do not cache 2275 // content with cert errors either. This is to prevent not reporting net 2276 // errors when loading a resource from the cache. When we load a page over 2277 // HTTPS with a cert error we show an SSL blocking page. If the user clicks 2278 // proceed we reload the resource ignoring the errors. The loaded resource 2279 // is then cached. If that resource is subsequently loaded from the cache, 2280 // no net error is reported (even though the cert status contains the actual 2281 // errors) and no SSL blocking page is shown. An alternative would be to 2282 // reverse-map the cert status to a net error and replay the net error. 2283 if ((cache_->mode() != RECORD && 2284 response_.headers->HasHeaderValue("cache-control", "no-store")) || 2285 net::IsCertStatusError(response_.ssl_info.cert_status)) { 2286 DoneWritingToEntry(false); 2287 ReportCacheActionFinish(); 2288 if (net_log_.IsLoggingAllEvents()) 2289 net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO); 2290 return OK; 2291 } 2292 2293 // When writing headers, we normally only write the non-transient 2294 // headers; when in record mode, record everything. 2295 bool skip_transient_headers = (cache_->mode() != RECORD); 2296 2297 if (truncated) 2298 DCHECK_EQ(200, response_.headers->response_code()); 2299 2300 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); 2301 response_.Persist(data->pickle(), skip_transient_headers, truncated); 2302 data->Done(); 2303 2304 io_buf_len_ = data->pickle()->size(); 2305 return ResetCacheIOStart(entry_->disk_entry->WriteData( 2306 kResponseInfoIndex, 0, data.get(), io_buf_len_, io_callback_, true)); 2307 } 2308 2309 int HttpCache::Transaction::AppendResponseDataToEntry( 2310 IOBuffer* data, int data_len, const CompletionCallback& callback) { 2311 if (!entry_ || !data_len) 2312 return data_len; 2313 2314 int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex); 2315 return WriteToEntry(kResponseContentIndex, current_size, data, data_len, 2316 callback); 2317 } 2318 2319 void HttpCache::Transaction::DoneWritingToEntry(bool success) { 2320 if (!entry_) 2321 return; 2322 2323 RecordHistograms(); 2324 2325 cache_->DoneWritingToEntry(entry_, success); 2326 entry_ = NULL; 2327 mode_ = NONE; // switch to 'pass through' mode 2328 } 2329 2330 int HttpCache::Transaction::OnCacheReadError(int result, bool restart) { 2331 DLOG(ERROR) << "ReadData failed: " << result; 2332 const int result_for_histogram = std::max(0, -result); 2333 if (restart) { 2334 UMA_HISTOGRAM_SPARSE_SLOWLY("HttpCache.ReadErrorRestartable", 2335 result_for_histogram); 2336 } else { 2337 UMA_HISTOGRAM_SPARSE_SLOWLY("HttpCache.ReadErrorNonRestartable", 2338 result_for_histogram); 2339 } 2340 2341 // Avoid using this entry in the future. 2342 if (cache_.get()) 2343 cache_->DoomActiveEntry(cache_key_); 2344 2345 if (restart) { 2346 DCHECK(!reading_); 2347 DCHECK(!network_trans_.get()); 2348 cache_->DoneWithEntry(entry_, this, false); 2349 entry_ = NULL; 2350 is_sparse_ = false; 2351 partial_.reset(); 2352 next_state_ = STATE_GET_BACKEND; 2353 return OK; 2354 } 2355 2356 return ERR_CACHE_READ_FAILURE; 2357 } 2358 2359 void HttpCache::Transaction::DoomPartialEntry(bool delete_object) { 2360 DVLOG(2) << "DoomPartialEntry"; 2361 int rv = cache_->DoomEntry(cache_key_, NULL); 2362 DCHECK_EQ(OK, rv); 2363 cache_->DoneWithEntry(entry_, this, false); 2364 entry_ = NULL; 2365 is_sparse_ = false; 2366 if (delete_object) 2367 partial_.reset(NULL); 2368 } 2369 2370 int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) { 2371 partial_->OnNetworkReadCompleted(result); 2372 2373 if (result == 0) { 2374 // We need to move on to the next range. 2375 ResetNetworkTransaction(); 2376 next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION; 2377 } 2378 return result; 2379 } 2380 2381 int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) { 2382 partial_->OnCacheReadCompleted(result); 2383 2384 if (result == 0 && mode_ == READ_WRITE) { 2385 // We need to move on to the next range. 2386 next_state_ = STATE_START_PARTIAL_CACHE_VALIDATION; 2387 } else if (result < 0) { 2388 return OnCacheReadError(result, false); 2389 } 2390 return result; 2391 } 2392 2393 int HttpCache::Transaction::DoRestartPartialRequest() { 2394 // The stored data cannot be used. Get rid of it and restart this request. 2395 // We need to also reset the |truncated_| flag as a new entry is created. 2396 DoomPartialEntry(!range_requested_); 2397 mode_ = WRITE; 2398 truncated_ = false; 2399 next_state_ = STATE_INIT_ENTRY; 2400 return OK; 2401 } 2402 2403 // Histogram data from the end of 2010 show the following distribution of 2404 // response headers: 2405 // 2406 // Content-Length............... 87% 2407 // Date......................... 98% 2408 // Last-Modified................ 49% 2409 // Etag......................... 19% 2410 // Accept-Ranges: bytes......... 25% 2411 // Accept-Ranges: none.......... 0.4% 2412 // Strong Validator............. 50% 2413 // Strong Validator + ranges.... 24% 2414 // Strong Validator + CL........ 49% 2415 // 2416 bool HttpCache::Transaction::CanResume(bool has_data) { 2417 // Double check that there is something worth keeping. 2418 if (has_data && !entry_->disk_entry->GetDataSize(kResponseContentIndex)) 2419 return false; 2420 2421 if (request_->method != "GET") 2422 return false; 2423 2424 if (response_.headers->GetContentLength() <= 0 || 2425 response_.headers->HasHeaderValue("Accept-Ranges", "none") || 2426 !response_.headers->HasStrongValidators()) { 2427 return false; 2428 } 2429 2430 return true; 2431 } 2432 2433 void HttpCache::Transaction::OnIOComplete(int result) { 2434 if (!cache_io_start_.is_null()) { 2435 base::TimeDelta cache_time = base::TimeTicks::Now() - cache_io_start_; 2436 cache_io_start_ = base::TimeTicks(); 2437 if (sensitivity_analysis_percent_increase_ > 0) { 2438 cache_time *= sensitivity_analysis_percent_increase_; 2439 cache_time /= 100; 2440 if (!defer_cache_sensitivity_delay_) { 2441 ScheduleDelayedLoop(cache_time, result); 2442 return; 2443 } else { 2444 deferred_cache_sensitivity_delay_ += cache_time; 2445 } 2446 } 2447 } 2448 DCHECK(cache_io_start_.is_null()); 2449 DoLoop(result); 2450 } 2451 2452 void HttpCache::Transaction::ScheduleDelayedLoop(base::TimeDelta delay, 2453 int result) { 2454 base::MessageLoop::current()->PostDelayedTask( 2455 FROM_HERE, 2456 base::Bind(&HttpCache::Transaction::RunDelayedLoop, 2457 weak_factory_.GetWeakPtr(), 2458 base::TimeTicks::Now(), 2459 delay, 2460 result), 2461 delay); 2462 } 2463 2464 void HttpCache::Transaction::RunDelayedLoop(base::TimeTicks delay_start_time, 2465 base::TimeDelta intended_delay, 2466 int result) { 2467 base::TimeDelta actual_delay = base::TimeTicks::Now() - delay_start_time; 2468 int64 ratio; 2469 int64 inverse_ratio; 2470 if (intended_delay.InMicroseconds() > 0) { 2471 ratio = 2472 100 * actual_delay.InMicroseconds() / intended_delay.InMicroseconds(); 2473 } else { 2474 ratio = 0; 2475 } 2476 if (actual_delay.InMicroseconds() > 0) { 2477 inverse_ratio = 2478 100 * intended_delay.InMicroseconds() / actual_delay.InMicroseconds(); 2479 } else { 2480 inverse_ratio = 0; 2481 } 2482 bool ratio_sample = base::RandInt(0, 99) < ratio; 2483 bool inverse_ratio_sample = base::RandInt(0, 99) < inverse_ratio; 2484 int intended_delay_ms = intended_delay.InMilliseconds(); 2485 UMA_HISTOGRAM_COUNTS_10000( 2486 "HttpCache.CacheSensitivityAnalysis_IntendedDelayMs", 2487 intended_delay_ms); 2488 if (ratio_sample) { 2489 UMA_HISTOGRAM_COUNTS_10000( 2490 "HttpCache.CacheSensitivityAnalysis_RatioByIntendedDelayMs", 2491 intended_delay_ms); 2492 } 2493 if (inverse_ratio_sample) { 2494 UMA_HISTOGRAM_COUNTS_10000( 2495 "HttpCache.CacheSensitivityAnalysis_InverseRatioByIntendedDelayMs", 2496 intended_delay_ms); 2497 } 2498 2499 DCHECK(cache_io_start_.is_null()); 2500 DCHECK(deferred_cache_sensitivity_delay_ == base::TimeDelta()); 2501 DoLoop(result); 2502 } 2503 2504 void HttpCache::Transaction::ReportCacheActionStart() { 2505 if (transaction_delegate_) 2506 transaction_delegate_->OnCacheActionStart(); 2507 } 2508 2509 void HttpCache::Transaction::ReportCacheActionFinish() { 2510 if (transaction_delegate_) 2511 transaction_delegate_->OnCacheActionFinish(); 2512 } 2513 2514 void HttpCache::Transaction::ReportNetworkActionStart() { 2515 if (transaction_delegate_) 2516 transaction_delegate_->OnNetworkActionStart(); 2517 } 2518 2519 void HttpCache::Transaction::ReportNetworkActionFinish() { 2520 if (transaction_delegate_) 2521 transaction_delegate_->OnNetworkActionFinish(); 2522 } 2523 2524 void HttpCache::Transaction::UpdateTransactionPattern( 2525 TransactionPattern new_transaction_pattern) { 2526 if (transaction_pattern_ == PATTERN_NOT_COVERED) 2527 return; 2528 DCHECK(transaction_pattern_ == PATTERN_UNDEFINED || 2529 new_transaction_pattern == PATTERN_NOT_COVERED); 2530 transaction_pattern_ = new_transaction_pattern; 2531 } 2532 2533 void HttpCache::Transaction::RecordHistograms() { 2534 DCHECK_NE(PATTERN_UNDEFINED, transaction_pattern_); 2535 if (!cache_.get() || !cache_->GetCurrentBackend() || 2536 cache_->GetCurrentBackend()->GetCacheType() != DISK_CACHE || 2537 cache_->mode() != NORMAL || request_->method != "GET") { 2538 return; 2539 } 2540 UMA_HISTOGRAM_ENUMERATION( 2541 "HttpCache.Pattern", transaction_pattern_, PATTERN_MAX); 2542 if (transaction_pattern_ == PATTERN_NOT_COVERED) 2543 return; 2544 DCHECK(!range_requested_); 2545 DCHECK(!first_cache_access_since_.is_null()); 2546 2547 TimeDelta total_time = base::TimeTicks::Now() - first_cache_access_since_; 2548 2549 UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone", total_time); 2550 2551 bool did_send_request = !send_request_since_.is_null(); 2552 DCHECK( 2553 (did_send_request && 2554 (transaction_pattern_ == PATTERN_ENTRY_NOT_CACHED || 2555 transaction_pattern_ == PATTERN_ENTRY_VALIDATED || 2556 transaction_pattern_ == PATTERN_ENTRY_UPDATED || 2557 transaction_pattern_ == PATTERN_ENTRY_CANT_CONDITIONALIZE)) || 2558 (!did_send_request && transaction_pattern_ == PATTERN_ENTRY_USED)); 2559 2560 if (!did_send_request) { 2561 DCHECK(transaction_pattern_ == PATTERN_ENTRY_USED); 2562 UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.Used", total_time); 2563 return; 2564 } 2565 2566 TimeDelta before_send_time = send_request_since_ - first_cache_access_since_; 2567 int before_send_percent = 2568 total_time.ToInternalValue() == 0 ? 0 2569 : before_send_time * 100 / total_time; 2570 DCHECK_LE(0, before_send_percent); 2571 DCHECK_GE(100, before_send_percent); 2572 2573 UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SentRequest", total_time); 2574 UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend", before_send_time); 2575 UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend", before_send_percent); 2576 2577 // TODO(gavinp): Remove or minimize these histograms, particularly the ones 2578 // below this comment after we have received initial data. 2579 switch (transaction_pattern_) { 2580 case PATTERN_ENTRY_CANT_CONDITIONALIZE: { 2581 UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.CantConditionalize", 2582 before_send_time); 2583 UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.CantConditionalize", 2584 before_send_percent); 2585 break; 2586 } 2587 case PATTERN_ENTRY_NOT_CACHED: { 2588 UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.NotCached", before_send_time); 2589 UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.NotCached", 2590 before_send_percent); 2591 break; 2592 } 2593 case PATTERN_ENTRY_VALIDATED: { 2594 UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Validated", before_send_time); 2595 UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.Validated", 2596 before_send_percent); 2597 break; 2598 } 2599 case PATTERN_ENTRY_UPDATED: { 2600 UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Updated", before_send_time); 2601 UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.Updated", 2602 before_send_percent); 2603 break; 2604 } 2605 default: 2606 NOTREACHED(); 2607 } 2608 } 2609 2610 int HttpCache::Transaction::ResetCacheIOStart(int return_value) { 2611 DCHECK(cache_io_start_.is_null()); 2612 if (return_value == ERR_IO_PENDING) 2613 cache_io_start_ = base::TimeTicks::Now(); 2614 return return_value; 2615 } 2616 2617 void HttpCache::Transaction::ResetNetworkTransaction() { 2618 DCHECK(!old_network_trans_load_timing_); 2619 DCHECK(network_trans_); 2620 LoadTimingInfo load_timing; 2621 if (network_trans_->GetLoadTimingInfo(&load_timing)) 2622 old_network_trans_load_timing_.reset(new LoadTimingInfo(load_timing)); 2623 network_trans_.reset(); 2624 } 2625 2626 } // namespace net 2627