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