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