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