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