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.h" 6 7 #include <algorithm> 8 9 #include "base/compiler_specific.h" 10 11 #if defined(OS_POSIX) 12 #include <unistd.h> 13 #endif 14 15 #include "base/bind.h" 16 #include "base/bind_helpers.h" 17 #include "base/callback.h" 18 #include "base/file_util.h" 19 #include "base/format_macros.h" 20 #include "base/location.h" 21 #include "base/memory/ref_counted.h" 22 #include "base/message_loop/message_loop.h" 23 #include "base/metrics/field_trial.h" 24 #include "base/pickle.h" 25 #include "base/stl_util.h" 26 #include "base/strings/string_number_conversions.h" 27 #include "base/strings/string_util.h" 28 #include "base/strings/stringprintf.h" 29 #include "base/threading/worker_pool.h" 30 #include "net/base/cache_type.h" 31 #include "net/base/io_buffer.h" 32 #include "net/base/load_flags.h" 33 #include "net/base/net_errors.h" 34 #include "net/base/upload_data_stream.h" 35 #include "net/disk_cache/disk_cache.h" 36 #include "net/http/disk_cache_based_quic_server_info.h" 37 #include "net/http/http_cache_transaction.h" 38 #include "net/http/http_network_layer.h" 39 #include "net/http/http_network_session.h" 40 #include "net/http/http_request_info.h" 41 #include "net/http/http_response_headers.h" 42 #include "net/http/http_response_info.h" 43 #include "net/http/http_util.h" 44 #include "net/quic/crypto/quic_server_info.h" 45 46 namespace { 47 48 // Adaptor to delete a file on a worker thread. 49 void DeletePath(base::FilePath path) { 50 base::DeleteFile(path, false); 51 } 52 53 } // namespace 54 55 namespace net { 56 57 HttpCache::DefaultBackend::DefaultBackend(CacheType type, 58 BackendType backend_type, 59 const base::FilePath& path, 60 int max_bytes, 61 base::MessageLoopProxy* thread) 62 : type_(type), 63 backend_type_(backend_type), 64 path_(path), 65 max_bytes_(max_bytes), 66 thread_(thread) { 67 } 68 69 HttpCache::DefaultBackend::~DefaultBackend() {} 70 71 // static 72 HttpCache::BackendFactory* HttpCache::DefaultBackend::InMemory(int max_bytes) { 73 return new DefaultBackend(MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT, 74 base::FilePath(), max_bytes, NULL); 75 } 76 77 int HttpCache::DefaultBackend::CreateBackend( 78 NetLog* net_log, scoped_ptr<disk_cache::Backend>* backend, 79 const CompletionCallback& callback) { 80 DCHECK_GE(max_bytes_, 0); 81 return disk_cache::CreateCacheBackend(type_, 82 backend_type_, 83 path_, 84 max_bytes_, 85 true, 86 thread_.get(), 87 net_log, 88 backend, 89 callback); 90 } 91 92 //----------------------------------------------------------------------------- 93 94 HttpCache::ActiveEntry::ActiveEntry(disk_cache::Entry* entry) 95 : disk_entry(entry), 96 writer(NULL), 97 will_process_pending_queue(false), 98 doomed(false) { 99 } 100 101 HttpCache::ActiveEntry::~ActiveEntry() { 102 if (disk_entry) { 103 disk_entry->Close(); 104 disk_entry = NULL; 105 } 106 } 107 108 //----------------------------------------------------------------------------- 109 110 // This structure keeps track of work items that are attempting to create or 111 // open cache entries or the backend itself. 112 struct HttpCache::PendingOp { 113 PendingOp() : disk_entry(NULL), writer(NULL) {} 114 ~PendingOp() {} 115 116 disk_cache::Entry* disk_entry; 117 scoped_ptr<disk_cache::Backend> backend; 118 WorkItem* writer; 119 CompletionCallback callback; // BackendCallback. 120 WorkItemList pending_queue; 121 }; 122 123 //----------------------------------------------------------------------------- 124 125 // The type of operation represented by a work item. 126 enum WorkItemOperation { 127 WI_CREATE_BACKEND, 128 WI_OPEN_ENTRY, 129 WI_CREATE_ENTRY, 130 WI_DOOM_ENTRY 131 }; 132 133 // A work item encapsulates a single request to the backend with all the 134 // information needed to complete that request. 135 class HttpCache::WorkItem { 136 public: 137 WorkItem(WorkItemOperation operation, Transaction* trans, ActiveEntry** entry) 138 : operation_(operation), 139 trans_(trans), 140 entry_(entry), 141 backend_(NULL) {} 142 WorkItem(WorkItemOperation operation, Transaction* trans, 143 const net::CompletionCallback& cb, disk_cache::Backend** backend) 144 : operation_(operation), 145 trans_(trans), 146 entry_(NULL), 147 callback_(cb), 148 backend_(backend) {} 149 ~WorkItem() {} 150 151 // Calls back the transaction with the result of the operation. 152 void NotifyTransaction(int result, ActiveEntry* entry) { 153 DCHECK(!entry || entry->disk_entry); 154 if (entry_) 155 *entry_ = entry; 156 if (trans_) 157 trans_->io_callback().Run(result); 158 } 159 160 // Notifies the caller about the operation completion. Returns true if the 161 // callback was invoked. 162 bool DoCallback(int result, disk_cache::Backend* backend) { 163 if (backend_) 164 *backend_ = backend; 165 if (!callback_.is_null()) { 166 callback_.Run(result); 167 return true; 168 } 169 return false; 170 } 171 172 WorkItemOperation operation() { return operation_; } 173 void ClearTransaction() { trans_ = NULL; } 174 void ClearEntry() { entry_ = NULL; } 175 void ClearCallback() { callback_.Reset(); } 176 bool Matches(Transaction* trans) const { return trans == trans_; } 177 bool IsValid() const { return trans_ || entry_ || !callback_.is_null(); } 178 179 private: 180 WorkItemOperation operation_; 181 Transaction* trans_; 182 ActiveEntry** entry_; 183 net::CompletionCallback callback_; // User callback. 184 disk_cache::Backend** backend_; 185 }; 186 187 //----------------------------------------------------------------------------- 188 189 // This class encapsulates a transaction whose only purpose is to write metadata 190 // to a given entry. 191 class HttpCache::MetadataWriter { 192 public: 193 explicit MetadataWriter(HttpCache::Transaction* trans) 194 : transaction_(trans), 195 verified_(false), 196 buf_len_(0) { 197 } 198 199 ~MetadataWriter() {} 200 201 // Implements the bulk of HttpCache::WriteMetadata. 202 void Write(const GURL& url, base::Time expected_response_time, IOBuffer* buf, 203 int buf_len); 204 205 private: 206 void VerifyResponse(int result); 207 void SelfDestroy(); 208 void OnIOComplete(int result); 209 210 scoped_ptr<HttpCache::Transaction> transaction_; 211 bool verified_; 212 scoped_refptr<IOBuffer> buf_; 213 int buf_len_; 214 base::Time expected_response_time_; 215 HttpRequestInfo request_info_; 216 DISALLOW_COPY_AND_ASSIGN(MetadataWriter); 217 }; 218 219 void HttpCache::MetadataWriter::Write(const GURL& url, 220 base::Time expected_response_time, 221 IOBuffer* buf, int buf_len) { 222 DCHECK_GT(buf_len, 0); 223 DCHECK(buf); 224 DCHECK(buf->data()); 225 request_info_.url = url; 226 request_info_.method = "GET"; 227 request_info_.load_flags = LOAD_ONLY_FROM_CACHE; 228 229 expected_response_time_ = expected_response_time; 230 buf_ = buf; 231 buf_len_ = buf_len; 232 verified_ = false; 233 234 int rv = transaction_->Start( 235 &request_info_, 236 base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this)), 237 BoundNetLog()); 238 if (rv != ERR_IO_PENDING) 239 VerifyResponse(rv); 240 } 241 242 void HttpCache::MetadataWriter::VerifyResponse(int result) { 243 verified_ = true; 244 if (result != OK) 245 return SelfDestroy(); 246 247 const HttpResponseInfo* response_info = transaction_->GetResponseInfo(); 248 DCHECK(response_info->was_cached); 249 if (response_info->response_time != expected_response_time_) 250 return SelfDestroy(); 251 252 result = transaction_->WriteMetadata( 253 buf_.get(), 254 buf_len_, 255 base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this))); 256 if (result != ERR_IO_PENDING) 257 SelfDestroy(); 258 } 259 260 void HttpCache::MetadataWriter::SelfDestroy() { 261 delete this; 262 } 263 264 void HttpCache::MetadataWriter::OnIOComplete(int result) { 265 if (!verified_) 266 return VerifyResponse(result); 267 SelfDestroy(); 268 } 269 270 //----------------------------------------------------------------------------- 271 272 class HttpCache::QuicServerInfoFactoryAdaptor : public QuicServerInfoFactory { 273 public: 274 QuicServerInfoFactoryAdaptor(HttpCache* http_cache) 275 : http_cache_(http_cache) { 276 } 277 278 virtual QuicServerInfo* GetForServer( 279 const QuicServerId& server_id) OVERRIDE { 280 return new DiskCacheBasedQuicServerInfo(server_id, http_cache_); 281 } 282 283 private: 284 HttpCache* const http_cache_; 285 }; 286 287 //----------------------------------------------------------------------------- 288 HttpCache::HttpCache(const net::HttpNetworkSession::Params& params, 289 BackendFactory* backend_factory) 290 : net_log_(params.net_log), 291 backend_factory_(backend_factory), 292 building_backend_(false), 293 mode_(NORMAL), 294 network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), 295 weak_factory_(this) { 296 SetupQuicServerInfoFactory(network_layer_->GetSession()); 297 } 298 299 300 // This call doesn't change the shared |session|'s QuicServerInfoFactory because 301 // |session| is shared. 302 HttpCache::HttpCache(HttpNetworkSession* session, 303 BackendFactory* backend_factory) 304 : net_log_(session->net_log()), 305 backend_factory_(backend_factory), 306 building_backend_(false), 307 mode_(NORMAL), 308 network_layer_(new HttpNetworkLayer(session)), 309 weak_factory_(this) { 310 } 311 312 HttpCache::HttpCache(HttpTransactionFactory* network_layer, 313 NetLog* net_log, 314 BackendFactory* backend_factory) 315 : net_log_(net_log), 316 backend_factory_(backend_factory), 317 building_backend_(false), 318 mode_(NORMAL), 319 network_layer_(network_layer), 320 weak_factory_(this) { 321 SetupQuicServerInfoFactory(network_layer_->GetSession()); 322 } 323 324 HttpCache::~HttpCache() { 325 // Transactions should see an invalid cache after this point; otherwise they 326 // could see an inconsistent object (half destroyed). 327 weak_factory_.InvalidateWeakPtrs(); 328 329 // If we have any active entries remaining, then we need to deactivate them. 330 // We may have some pending calls to OnProcessPendingQueue, but since those 331 // won't run (due to our destruction), we can simply ignore the corresponding 332 // will_process_pending_queue flag. 333 while (!active_entries_.empty()) { 334 ActiveEntry* entry = active_entries_.begin()->second; 335 entry->will_process_pending_queue = false; 336 entry->pending_queue.clear(); 337 entry->readers.clear(); 338 entry->writer = NULL; 339 DeactivateEntry(entry); 340 } 341 342 STLDeleteElements(&doomed_entries_); 343 344 // Before deleting pending_ops_, we have to make sure that the disk cache is 345 // done with said operations, or it will attempt to use deleted data. 346 disk_cache_.reset(); 347 348 PendingOpsMap::iterator pending_it = pending_ops_.begin(); 349 for (; pending_it != pending_ops_.end(); ++pending_it) { 350 // We are not notifying the transactions about the cache going away, even 351 // though they are waiting for a callback that will never fire. 352 PendingOp* pending_op = pending_it->second; 353 delete pending_op->writer; 354 bool delete_pending_op = true; 355 if (building_backend_) { 356 // If we don't have a backend, when its construction finishes it will 357 // deliver the callbacks. 358 if (!pending_op->callback.is_null()) { 359 // If not null, the callback will delete the pending operation later. 360 delete_pending_op = false; 361 } 362 } else { 363 pending_op->callback.Reset(); 364 } 365 366 STLDeleteElements(&pending_op->pending_queue); 367 if (delete_pending_op) 368 delete pending_op; 369 } 370 } 371 372 int HttpCache::GetBackend(disk_cache::Backend** backend, 373 const CompletionCallback& callback) { 374 DCHECK(!callback.is_null()); 375 376 if (disk_cache_.get()) { 377 *backend = disk_cache_.get(); 378 return OK; 379 } 380 381 return CreateBackend(backend, callback); 382 } 383 384 disk_cache::Backend* HttpCache::GetCurrentBackend() const { 385 return disk_cache_.get(); 386 } 387 388 // static 389 bool HttpCache::ParseResponseInfo(const char* data, int len, 390 HttpResponseInfo* response_info, 391 bool* response_truncated) { 392 Pickle pickle(data, len); 393 return response_info->InitFromPickle(pickle, response_truncated); 394 } 395 396 void HttpCache::WriteMetadata(const GURL& url, 397 RequestPriority priority, 398 base::Time expected_response_time, 399 IOBuffer* buf, 400 int buf_len) { 401 if (!buf_len) 402 return; 403 404 // Do lazy initialization of disk cache if needed. 405 if (!disk_cache_.get()) { 406 // We don't care about the result. 407 CreateBackend(NULL, net::CompletionCallback()); 408 } 409 410 HttpCache::Transaction* trans = 411 new HttpCache::Transaction(priority, this); 412 MetadataWriter* writer = new MetadataWriter(trans); 413 414 // The writer will self destruct when done. 415 writer->Write(url, expected_response_time, buf, buf_len); 416 } 417 418 void HttpCache::CloseAllConnections() { 419 HttpNetworkSession* session = GetSession(); 420 if (session) 421 session->CloseAllConnections(); 422 } 423 424 void HttpCache::CloseIdleConnections() { 425 HttpNetworkSession* session = GetSession(); 426 if (session) 427 session->CloseIdleConnections(); 428 } 429 430 void HttpCache::OnExternalCacheHit(const GURL& url, 431 const std::string& http_method) { 432 if (!disk_cache_.get()) 433 return; 434 435 HttpRequestInfo request_info; 436 request_info.url = url; 437 request_info.method = http_method; 438 std::string key = GenerateCacheKey(&request_info); 439 disk_cache_->OnExternalCacheHit(key); 440 } 441 442 void HttpCache::InitializeInfiniteCache(const base::FilePath& path) { 443 if (base::FieldTrialList::FindFullName("InfiniteCache") != "Yes") 444 return; 445 base::WorkerPool::PostTask(FROM_HERE, base::Bind(&DeletePath, path), true); 446 } 447 448 int HttpCache::CreateTransaction(RequestPriority priority, 449 scoped_ptr<HttpTransaction>* trans) { 450 // Do lazy initialization of disk cache if needed. 451 if (!disk_cache_.get()) { 452 // We don't care about the result. 453 CreateBackend(NULL, net::CompletionCallback()); 454 } 455 456 trans->reset(new HttpCache::Transaction(priority, this)); 457 return OK; 458 } 459 460 HttpCache* HttpCache::GetCache() { 461 return this; 462 } 463 464 HttpNetworkSession* HttpCache::GetSession() { 465 return network_layer_->GetSession(); 466 } 467 468 scoped_ptr<HttpTransactionFactory> 469 HttpCache::SetHttpNetworkTransactionFactoryForTesting( 470 scoped_ptr<HttpTransactionFactory> new_network_layer) { 471 scoped_ptr<HttpTransactionFactory> old_network_layer(network_layer_.Pass()); 472 network_layer_ = new_network_layer.Pass(); 473 return old_network_layer.Pass(); 474 } 475 476 //----------------------------------------------------------------------------- 477 478 int HttpCache::CreateBackend(disk_cache::Backend** backend, 479 const net::CompletionCallback& callback) { 480 if (!backend_factory_.get()) 481 return ERR_FAILED; 482 483 building_backend_ = true; 484 485 scoped_ptr<WorkItem> item(new WorkItem(WI_CREATE_BACKEND, NULL, callback, 486 backend)); 487 488 // This is the only operation that we can do that is not related to any given 489 // entry, so we use an empty key for it. 490 PendingOp* pending_op = GetPendingOp(std::string()); 491 if (pending_op->writer) { 492 if (!callback.is_null()) 493 pending_op->pending_queue.push_back(item.release()); 494 return ERR_IO_PENDING; 495 } 496 497 DCHECK(pending_op->pending_queue.empty()); 498 499 pending_op->writer = item.release(); 500 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete, 501 GetWeakPtr(), pending_op); 502 503 int rv = backend_factory_->CreateBackend(net_log_, &pending_op->backend, 504 pending_op->callback); 505 if (rv != ERR_IO_PENDING) { 506 pending_op->writer->ClearCallback(); 507 pending_op->callback.Run(rv); 508 } 509 510 return rv; 511 } 512 513 int HttpCache::GetBackendForTransaction(Transaction* trans) { 514 if (disk_cache_.get()) 515 return OK; 516 517 if (!building_backend_) 518 return ERR_FAILED; 519 520 WorkItem* item = new WorkItem( 521 WI_CREATE_BACKEND, trans, net::CompletionCallback(), NULL); 522 PendingOp* pending_op = GetPendingOp(std::string()); 523 DCHECK(pending_op->writer); 524 pending_op->pending_queue.push_back(item); 525 return ERR_IO_PENDING; 526 } 527 528 // Generate a key that can be used inside the cache. 529 std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) { 530 // Strip out the reference, username, and password sections of the URL. 531 std::string url = HttpUtil::SpecForRequest(request->url); 532 533 DCHECK(mode_ != DISABLE); 534 if (mode_ == NORMAL) { 535 // No valid URL can begin with numerals, so we should not have to worry 536 // about collisions with normal URLs. 537 if (request->upload_data_stream && 538 request->upload_data_stream->identifier()) { 539 url.insert(0, base::StringPrintf( 540 "%" PRId64 "/", request->upload_data_stream->identifier())); 541 } 542 return url; 543 } 544 545 // In playback and record mode, we cache everything. 546 547 // Lazily initialize. 548 if (playback_cache_map_ == NULL) 549 playback_cache_map_.reset(new PlaybackCacheMap()); 550 551 // Each time we request an item from the cache, we tag it with a 552 // generation number. During playback, multiple fetches for the same 553 // item will use the same generation number and pull the proper 554 // instance of an URL from the cache. 555 int generation = 0; 556 DCHECK(playback_cache_map_ != NULL); 557 if (playback_cache_map_->find(url) != playback_cache_map_->end()) 558 generation = (*playback_cache_map_)[url]; 559 (*playback_cache_map_)[url] = generation + 1; 560 561 // The key into the cache is GENERATION # + METHOD + URL. 562 std::string result = base::IntToString(generation); 563 result.append(request->method); 564 result.append(url); 565 return result; 566 } 567 568 void HttpCache::DoomActiveEntry(const std::string& key) { 569 ActiveEntriesMap::iterator it = active_entries_.find(key); 570 if (it == active_entries_.end()) 571 return; 572 573 // This is not a performance critical operation, this is handling an error 574 // condition so it is OK to look up the entry again. 575 int rv = DoomEntry(key, NULL); 576 DCHECK_EQ(OK, rv); 577 } 578 579 int HttpCache::DoomEntry(const std::string& key, Transaction* trans) { 580 // Need to abandon the ActiveEntry, but any transaction attached to the entry 581 // should not be impacted. Dooming an entry only means that it will no 582 // longer be returned by FindActiveEntry (and it will also be destroyed once 583 // all consumers are finished with the entry). 584 ActiveEntriesMap::iterator it = active_entries_.find(key); 585 if (it == active_entries_.end()) { 586 DCHECK(trans); 587 return AsyncDoomEntry(key, trans); 588 } 589 590 ActiveEntry* entry = it->second; 591 active_entries_.erase(it); 592 593 // We keep track of doomed entries so that we can ensure that they are 594 // cleaned up properly when the cache is destroyed. 595 doomed_entries_.insert(entry); 596 597 entry->disk_entry->Doom(); 598 entry->doomed = true; 599 600 DCHECK(entry->writer || !entry->readers.empty()); 601 return OK; 602 } 603 604 int HttpCache::AsyncDoomEntry(const std::string& key, Transaction* trans) { 605 WorkItem* item = new WorkItem(WI_DOOM_ENTRY, trans, NULL); 606 PendingOp* pending_op = GetPendingOp(key); 607 if (pending_op->writer) { 608 pending_op->pending_queue.push_back(item); 609 return ERR_IO_PENDING; 610 } 611 612 DCHECK(pending_op->pending_queue.empty()); 613 614 pending_op->writer = item; 615 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete, 616 GetWeakPtr(), pending_op); 617 618 int rv = disk_cache_->DoomEntry(key, pending_op->callback); 619 if (rv != ERR_IO_PENDING) { 620 item->ClearTransaction(); 621 pending_op->callback.Run(rv); 622 } 623 624 return rv; 625 } 626 627 void HttpCache::DoomMainEntryForUrl(const GURL& url) { 628 if (!disk_cache_) 629 return; 630 631 HttpRequestInfo temp_info; 632 temp_info.url = url; 633 temp_info.method = "GET"; 634 std::string key = GenerateCacheKey(&temp_info); 635 636 // Defer to DoomEntry if there is an active entry, otherwise call 637 // AsyncDoomEntry without triggering a callback. 638 if (active_entries_.count(key)) 639 DoomEntry(key, NULL); 640 else 641 AsyncDoomEntry(key, NULL); 642 } 643 644 void HttpCache::FinalizeDoomedEntry(ActiveEntry* entry) { 645 DCHECK(entry->doomed); 646 DCHECK(!entry->writer); 647 DCHECK(entry->readers.empty()); 648 DCHECK(entry->pending_queue.empty()); 649 650 ActiveEntriesSet::iterator it = doomed_entries_.find(entry); 651 DCHECK(it != doomed_entries_.end()); 652 doomed_entries_.erase(it); 653 654 delete entry; 655 } 656 657 HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { 658 ActiveEntriesMap::const_iterator it = active_entries_.find(key); 659 return it != active_entries_.end() ? it->second : NULL; 660 } 661 662 HttpCache::ActiveEntry* HttpCache::ActivateEntry( 663 disk_cache::Entry* disk_entry) { 664 DCHECK(!FindActiveEntry(disk_entry->GetKey())); 665 ActiveEntry* entry = new ActiveEntry(disk_entry); 666 active_entries_[disk_entry->GetKey()] = entry; 667 return entry; 668 } 669 670 void HttpCache::DeactivateEntry(ActiveEntry* entry) { 671 DCHECK(!entry->will_process_pending_queue); 672 DCHECK(!entry->doomed); 673 DCHECK(!entry->writer); 674 DCHECK(entry->disk_entry); 675 DCHECK(entry->readers.empty()); 676 DCHECK(entry->pending_queue.empty()); 677 678 std::string key = entry->disk_entry->GetKey(); 679 if (key.empty()) 680 return SlowDeactivateEntry(entry); 681 682 ActiveEntriesMap::iterator it = active_entries_.find(key); 683 DCHECK(it != active_entries_.end()); 684 DCHECK(it->second == entry); 685 686 active_entries_.erase(it); 687 delete entry; 688 } 689 690 // We don't know this entry's key so we have to find it without it. 691 void HttpCache::SlowDeactivateEntry(ActiveEntry* entry) { 692 for (ActiveEntriesMap::iterator it = active_entries_.begin(); 693 it != active_entries_.end(); ++it) { 694 if (it->second == entry) { 695 active_entries_.erase(it); 696 delete entry; 697 break; 698 } 699 } 700 } 701 702 HttpCache::PendingOp* HttpCache::GetPendingOp(const std::string& key) { 703 DCHECK(!FindActiveEntry(key)); 704 705 PendingOpsMap::const_iterator it = pending_ops_.find(key); 706 if (it != pending_ops_.end()) 707 return it->second; 708 709 PendingOp* operation = new PendingOp(); 710 pending_ops_[key] = operation; 711 return operation; 712 } 713 714 void HttpCache::DeletePendingOp(PendingOp* pending_op) { 715 std::string key; 716 if (pending_op->disk_entry) 717 key = pending_op->disk_entry->GetKey(); 718 719 if (!key.empty()) { 720 PendingOpsMap::iterator it = pending_ops_.find(key); 721 DCHECK(it != pending_ops_.end()); 722 pending_ops_.erase(it); 723 } else { 724 for (PendingOpsMap::iterator it = pending_ops_.begin(); 725 it != pending_ops_.end(); ++it) { 726 if (it->second == pending_op) { 727 pending_ops_.erase(it); 728 break; 729 } 730 } 731 } 732 DCHECK(pending_op->pending_queue.empty()); 733 734 delete pending_op; 735 } 736 737 int HttpCache::OpenEntry(const std::string& key, ActiveEntry** entry, 738 Transaction* trans) { 739 ActiveEntry* active_entry = FindActiveEntry(key); 740 if (active_entry) { 741 *entry = active_entry; 742 return OK; 743 } 744 745 WorkItem* item = new WorkItem(WI_OPEN_ENTRY, trans, entry); 746 PendingOp* pending_op = GetPendingOp(key); 747 if (pending_op->writer) { 748 pending_op->pending_queue.push_back(item); 749 return ERR_IO_PENDING; 750 } 751 752 DCHECK(pending_op->pending_queue.empty()); 753 754 pending_op->writer = item; 755 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete, 756 GetWeakPtr(), pending_op); 757 758 int rv = disk_cache_->OpenEntry(key, &(pending_op->disk_entry), 759 pending_op->callback); 760 if (rv != ERR_IO_PENDING) { 761 item->ClearTransaction(); 762 pending_op->callback.Run(rv); 763 } 764 765 return rv; 766 } 767 768 int HttpCache::CreateEntry(const std::string& key, ActiveEntry** entry, 769 Transaction* trans) { 770 if (FindActiveEntry(key)) { 771 return ERR_CACHE_RACE; 772 } 773 774 WorkItem* item = new WorkItem(WI_CREATE_ENTRY, trans, entry); 775 PendingOp* pending_op = GetPendingOp(key); 776 if (pending_op->writer) { 777 pending_op->pending_queue.push_back(item); 778 return ERR_IO_PENDING; 779 } 780 781 DCHECK(pending_op->pending_queue.empty()); 782 783 pending_op->writer = item; 784 pending_op->callback = base::Bind(&HttpCache::OnPendingOpComplete, 785 GetWeakPtr(), pending_op); 786 787 int rv = disk_cache_->CreateEntry(key, &(pending_op->disk_entry), 788 pending_op->callback); 789 if (rv != ERR_IO_PENDING) { 790 item->ClearTransaction(); 791 pending_op->callback.Run(rv); 792 } 793 794 return rv; 795 } 796 797 void HttpCache::DestroyEntry(ActiveEntry* entry) { 798 if (entry->doomed) { 799 FinalizeDoomedEntry(entry); 800 } else { 801 DeactivateEntry(entry); 802 } 803 } 804 805 int HttpCache::AddTransactionToEntry(ActiveEntry* entry, Transaction* trans) { 806 DCHECK(entry); 807 DCHECK(entry->disk_entry); 808 809 // We implement a basic reader/writer lock for the disk cache entry. If 810 // there is already a writer, then everyone has to wait for the writer to 811 // finish before they can access the cache entry. There can be multiple 812 // readers. 813 // 814 // NOTE: If the transaction can only write, then the entry should not be in 815 // use (since any existing entry should have already been doomed). 816 817 if (entry->writer || entry->will_process_pending_queue) { 818 entry->pending_queue.push_back(trans); 819 return ERR_IO_PENDING; 820 } 821 822 if (trans->mode() & Transaction::WRITE) { 823 // transaction needs exclusive access to the entry 824 if (entry->readers.empty()) { 825 entry->writer = trans; 826 } else { 827 entry->pending_queue.push_back(trans); 828 return ERR_IO_PENDING; 829 } 830 } else { 831 // transaction needs read access to the entry 832 entry->readers.push_back(trans); 833 } 834 835 // We do this before calling EntryAvailable to force any further calls to 836 // AddTransactionToEntry to add their transaction to the pending queue, which 837 // ensures FIFO ordering. 838 if (!entry->writer && !entry->pending_queue.empty()) 839 ProcessPendingQueue(entry); 840 841 return OK; 842 } 843 844 void HttpCache::DoneWithEntry(ActiveEntry* entry, Transaction* trans, 845 bool cancel) { 846 // If we already posted a task to move on to the next transaction and this was 847 // the writer, there is nothing to cancel. 848 if (entry->will_process_pending_queue && entry->readers.empty()) 849 return; 850 851 if (entry->writer) { 852 DCHECK(trans == entry->writer); 853 854 // Assume there was a failure. 855 bool success = false; 856 if (cancel) { 857 DCHECK(entry->disk_entry); 858 // This is a successful operation in the sense that we want to keep the 859 // entry. 860 success = trans->AddTruncatedFlag(); 861 // The previous operation may have deleted the entry. 862 if (!trans->entry()) 863 return; 864 } 865 DoneWritingToEntry(entry, success); 866 } else { 867 DoneReadingFromEntry(entry, trans); 868 } 869 } 870 871 void HttpCache::DoneWritingToEntry(ActiveEntry* entry, bool success) { 872 DCHECK(entry->readers.empty()); 873 874 entry->writer = NULL; 875 876 if (success) { 877 ProcessPendingQueue(entry); 878 } else { 879 DCHECK(!entry->will_process_pending_queue); 880 881 // We failed to create this entry. 882 TransactionList pending_queue; 883 pending_queue.swap(entry->pending_queue); 884 885 entry->disk_entry->Doom(); 886 DestroyEntry(entry); 887 888 // We need to do something about these pending entries, which now need to 889 // be added to a new entry. 890 while (!pending_queue.empty()) { 891 // ERR_CACHE_RACE causes the transaction to restart the whole process. 892 pending_queue.front()->io_callback().Run(ERR_CACHE_RACE); 893 pending_queue.pop_front(); 894 } 895 } 896 } 897 898 void HttpCache::DoneReadingFromEntry(ActiveEntry* entry, Transaction* trans) { 899 DCHECK(!entry->writer); 900 901 TransactionList::iterator it = 902 std::find(entry->readers.begin(), entry->readers.end(), trans); 903 DCHECK(it != entry->readers.end()); 904 905 entry->readers.erase(it); 906 907 ProcessPendingQueue(entry); 908 } 909 910 void HttpCache::ConvertWriterToReader(ActiveEntry* entry) { 911 DCHECK(entry->writer); 912 DCHECK(entry->writer->mode() == Transaction::READ_WRITE); 913 DCHECK(entry->readers.empty()); 914 915 Transaction* trans = entry->writer; 916 917 entry->writer = NULL; 918 entry->readers.push_back(trans); 919 920 ProcessPendingQueue(entry); 921 } 922 923 LoadState HttpCache::GetLoadStateForPendingTransaction( 924 const Transaction* trans) { 925 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key()); 926 if (i == active_entries_.end()) { 927 // If this is really a pending transaction, and it is not part of 928 // active_entries_, we should be creating the backend or the entry. 929 return LOAD_STATE_WAITING_FOR_CACHE; 930 } 931 932 Transaction* writer = i->second->writer; 933 return writer ? writer->GetWriterLoadState() : LOAD_STATE_WAITING_FOR_CACHE; 934 } 935 936 void HttpCache::RemovePendingTransaction(Transaction* trans) { 937 ActiveEntriesMap::const_iterator i = active_entries_.find(trans->key()); 938 bool found = false; 939 if (i != active_entries_.end()) 940 found = RemovePendingTransactionFromEntry(i->second, trans); 941 942 if (found) 943 return; 944 945 if (building_backend_) { 946 PendingOpsMap::const_iterator j = pending_ops_.find(std::string()); 947 if (j != pending_ops_.end()) 948 found = RemovePendingTransactionFromPendingOp(j->second, trans); 949 950 if (found) 951 return; 952 } 953 954 PendingOpsMap::const_iterator j = pending_ops_.find(trans->key()); 955 if (j != pending_ops_.end()) 956 found = RemovePendingTransactionFromPendingOp(j->second, trans); 957 958 if (found) 959 return; 960 961 ActiveEntriesSet::iterator k = doomed_entries_.begin(); 962 for (; k != doomed_entries_.end() && !found; ++k) 963 found = RemovePendingTransactionFromEntry(*k, trans); 964 965 DCHECK(found) << "Pending transaction not found"; 966 } 967 968 bool HttpCache::RemovePendingTransactionFromEntry(ActiveEntry* entry, 969 Transaction* trans) { 970 TransactionList& pending_queue = entry->pending_queue; 971 972 TransactionList::iterator j = 973 find(pending_queue.begin(), pending_queue.end(), trans); 974 if (j == pending_queue.end()) 975 return false; 976 977 pending_queue.erase(j); 978 return true; 979 } 980 981 bool HttpCache::RemovePendingTransactionFromPendingOp(PendingOp* pending_op, 982 Transaction* trans) { 983 if (pending_op->writer->Matches(trans)) { 984 pending_op->writer->ClearTransaction(); 985 pending_op->writer->ClearEntry(); 986 return true; 987 } 988 WorkItemList& pending_queue = pending_op->pending_queue; 989 990 WorkItemList::iterator it = pending_queue.begin(); 991 for (; it != pending_queue.end(); ++it) { 992 if ((*it)->Matches(trans)) { 993 delete *it; 994 pending_queue.erase(it); 995 return true; 996 } 997 } 998 return false; 999 } 1000 1001 void HttpCache::SetupQuicServerInfoFactory(HttpNetworkSession* session) { 1002 if (session && session->params().enable_quic_persist_server_info && 1003 !session->quic_stream_factory()->has_quic_server_info_factory()) { 1004 DCHECK(!quic_server_info_factory_); 1005 quic_server_info_factory_.reset(new QuicServerInfoFactoryAdaptor(this)); 1006 session->quic_stream_factory()->set_quic_server_info_factory( 1007 quic_server_info_factory_.get()); 1008 } 1009 } 1010 1011 void HttpCache::ProcessPendingQueue(ActiveEntry* entry) { 1012 // Multiple readers may finish with an entry at once, so we want to batch up 1013 // calls to OnProcessPendingQueue. This flag also tells us that we should 1014 // not delete the entry before OnProcessPendingQueue runs. 1015 if (entry->will_process_pending_queue) 1016 return; 1017 entry->will_process_pending_queue = true; 1018 1019 base::MessageLoop::current()->PostTask( 1020 FROM_HERE, 1021 base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry)); 1022 } 1023 1024 void HttpCache::OnProcessPendingQueue(ActiveEntry* entry) { 1025 entry->will_process_pending_queue = false; 1026 DCHECK(!entry->writer); 1027 1028 // If no one is interested in this entry, then we can deactivate it. 1029 if (entry->pending_queue.empty()) { 1030 if (entry->readers.empty()) 1031 DestroyEntry(entry); 1032 return; 1033 } 1034 1035 // Promote next transaction from the pending queue. 1036 Transaction* next = entry->pending_queue.front(); 1037 if ((next->mode() & Transaction::WRITE) && !entry->readers.empty()) 1038 return; // Have to wait. 1039 1040 entry->pending_queue.erase(entry->pending_queue.begin()); 1041 1042 int rv = AddTransactionToEntry(entry, next); 1043 if (rv != ERR_IO_PENDING) { 1044 next->io_callback().Run(rv); 1045 } 1046 } 1047 1048 void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { 1049 WorkItemOperation op = pending_op->writer->operation(); 1050 1051 // Completing the creation of the backend is simpler than the other cases. 1052 if (op == WI_CREATE_BACKEND) 1053 return OnBackendCreated(result, pending_op); 1054 1055 scoped_ptr<WorkItem> item(pending_op->writer); 1056 bool fail_requests = false; 1057 1058 ActiveEntry* entry = NULL; 1059 std::string key; 1060 if (result == OK) { 1061 if (op == WI_DOOM_ENTRY) { 1062 // Anything after a Doom has to be restarted. 1063 fail_requests = true; 1064 } else if (item->IsValid()) { 1065 key = pending_op->disk_entry->GetKey(); 1066 entry = ActivateEntry(pending_op->disk_entry); 1067 } else { 1068 // The writer transaction is gone. 1069 if (op == WI_CREATE_ENTRY) 1070 pending_op->disk_entry->Doom(); 1071 pending_op->disk_entry->Close(); 1072 pending_op->disk_entry = NULL; 1073 fail_requests = true; 1074 } 1075 } 1076 1077 // We are about to notify a bunch of transactions, and they may decide to 1078 // re-issue a request (or send a different one). If we don't delete 1079 // pending_op, the new request will be appended to the end of the list, and 1080 // we'll see it again from this point before it has a chance to complete (and 1081 // we'll be messing out the request order). The down side is that if for some 1082 // reason notifying request A ends up cancelling request B (for the same key), 1083 // we won't find request B anywhere (because it would be in a local variable 1084 // here) and that's bad. If there is a chance for that to happen, we'll have 1085 // to move the callback used to be a CancelableCallback. By the way, for this 1086 // to happen the action (to cancel B) has to be synchronous to the 1087 // notification for request A. 1088 WorkItemList pending_items; 1089 pending_items.swap(pending_op->pending_queue); 1090 DeletePendingOp(pending_op); 1091 1092 item->NotifyTransaction(result, entry); 1093 1094 while (!pending_items.empty()) { 1095 item.reset(pending_items.front()); 1096 pending_items.pop_front(); 1097 1098 if (item->operation() == WI_DOOM_ENTRY) { 1099 // A queued doom request is always a race. 1100 fail_requests = true; 1101 } else if (result == OK) { 1102 entry = FindActiveEntry(key); 1103 if (!entry) 1104 fail_requests = true; 1105 } 1106 1107 if (fail_requests) { 1108 item->NotifyTransaction(ERR_CACHE_RACE, NULL); 1109 continue; 1110 } 1111 1112 if (item->operation() == WI_CREATE_ENTRY) { 1113 if (result == OK) { 1114 // A second Create request, but the first request succeeded. 1115 item->NotifyTransaction(ERR_CACHE_CREATE_FAILURE, NULL); 1116 } else { 1117 if (op != WI_CREATE_ENTRY) { 1118 // Failed Open followed by a Create. 1119 item->NotifyTransaction(ERR_CACHE_RACE, NULL); 1120 fail_requests = true; 1121 } else { 1122 item->NotifyTransaction(result, entry); 1123 } 1124 } 1125 } else { 1126 if (op == WI_CREATE_ENTRY && result != OK) { 1127 // Failed Create followed by an Open. 1128 item->NotifyTransaction(ERR_CACHE_RACE, NULL); 1129 fail_requests = true; 1130 } else { 1131 item->NotifyTransaction(result, entry); 1132 } 1133 } 1134 } 1135 } 1136 1137 // static 1138 void HttpCache::OnPendingOpComplete(const base::WeakPtr<HttpCache>& cache, 1139 PendingOp* pending_op, 1140 int rv) { 1141 if (cache.get()) { 1142 cache->OnIOComplete(rv, pending_op); 1143 } else { 1144 // The callback was cancelled so we should delete the pending_op that 1145 // was used with this callback. 1146 delete pending_op; 1147 } 1148 } 1149 1150 void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) { 1151 scoped_ptr<WorkItem> item(pending_op->writer); 1152 WorkItemOperation op = item->operation(); 1153 DCHECK_EQ(WI_CREATE_BACKEND, op); 1154 1155 // We don't need the callback anymore. 1156 pending_op->callback.Reset(); 1157 1158 if (backend_factory_.get()) { 1159 // We may end up calling OnBackendCreated multiple times if we have pending 1160 // work items. The first call saves the backend and releases the factory, 1161 // and the last call clears building_backend_. 1162 backend_factory_.reset(); // Reclaim memory. 1163 if (result == OK) 1164 disk_cache_ = pending_op->backend.Pass(); 1165 } 1166 1167 if (!pending_op->pending_queue.empty()) { 1168 WorkItem* pending_item = pending_op->pending_queue.front(); 1169 pending_op->pending_queue.pop_front(); 1170 DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation()); 1171 1172 // We want to process a single callback at a time, because the cache may 1173 // go away from the callback. 1174 pending_op->writer = pending_item; 1175 1176 base::MessageLoop::current()->PostTask( 1177 FROM_HERE, 1178 base::Bind(&HttpCache::OnBackendCreated, GetWeakPtr(), 1179 result, pending_op)); 1180 } else { 1181 building_backend_ = false; 1182 DeletePendingOp(pending_op); 1183 } 1184 1185 // The cache may be gone when we return from the callback. 1186 if (!item->DoCallback(result, disk_cache_.get())) 1187 item->NotifyTransaction(result, NULL); 1188 } 1189 1190 } // namespace net 1191