| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/service_worker/service_worker_cache.h" | 5 #include "content/browser/service_worker/service_worker_cache.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/guid.h" | 10 #include "base/guid.h" |
| (...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 643 new ServiceWorkerCache(path, request_context, blob_context)); | 643 new ServiceWorkerCache(path, request_context, blob_context)); |
| 644 } | 644 } |
| 645 | 645 |
| 646 ServiceWorkerCache::~ServiceWorkerCache() { | 646 ServiceWorkerCache::~ServiceWorkerCache() { |
| 647 } | 647 } |
| 648 | 648 |
| 649 base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() { | 649 base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() { |
| 650 return weak_ptr_factory_.GetWeakPtr(); | 650 return weak_ptr_factory_.GetWeakPtr(); |
| 651 } | 651 } |
| 652 | 652 |
| 653 void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) { | |
| 654 DCHECK(!backend_); | |
| 655 | |
| 656 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction. | |
| 657 net::CacheType cache_type = | |
| 658 path_.empty() ? net::MEMORY_CACHE : net::APP_CACHE; | |
| 659 | |
| 660 scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr()); | |
| 661 | |
| 662 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below. | |
| 663 ScopedBackendPtr* backend = backend_ptr.get(); | |
| 664 | |
| 665 net::CompletionCallback create_cache_callback = | |
| 666 base::Bind(CreateBackendDidCreate, | |
| 667 callback, | |
| 668 base::Passed(backend_ptr.Pass()), | |
| 669 weak_ptr_factory_.GetWeakPtr()); | |
| 670 | |
| 671 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore | |
| 672 // has for disk caches. | |
| 673 // TODO(jkarlin): Switch to SimpleCache after it supports APP_CACHE and after | |
| 674 // debugging why the QuickStressBody unittest fails with it. | |
| 675 int rv = disk_cache::CreateCacheBackend( | |
| 676 cache_type, | |
| 677 net::CACHE_BACKEND_SIMPLE, | |
| 678 path_, | |
| 679 kMaxCacheBytes, | |
| 680 false, /* force */ | |
| 681 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(), | |
| 682 NULL, | |
| 683 backend, | |
| 684 create_cache_callback); | |
| 685 if (rv != net::ERR_IO_PENDING) | |
| 686 create_cache_callback.Run(rv); | |
| 687 } | |
| 688 | |
| 689 void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request, | 653 void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request, |
| 690 scoped_ptr<ServiceWorkerResponse> response, | 654 scoped_ptr<ServiceWorkerResponse> response, |
| 691 const ErrorCallback& callback) { | 655 const ErrorCallback& callback) { |
| 692 DCHECK(backend_); | |
| 693 | |
| 694 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); | |
| 695 | |
| 696 disk_cache::Entry** entry_ptr = entry.get(); | |
| 697 | |
| 698 scoped_ptr<storage::BlobDataHandle> blob_data_handle; | 656 scoped_ptr<storage::BlobDataHandle> blob_data_handle; |
| 699 | 657 |
| 700 if (!response->blob_uuid.empty()) { | 658 if (!response->blob_uuid.empty()) { |
| 701 if (!blob_storage_context_) { | 659 if (!blob_storage_context_) { |
| 702 callback.Run(ErrorTypeStorage); | 660 callback.Run(ErrorTypeStorage); |
| 703 return; | 661 return; |
| 704 } | 662 } |
| 705 blob_data_handle = | 663 blob_data_handle = |
| 706 blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid); | 664 blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid); |
| 707 if (!blob_data_handle) { | 665 if (!blob_data_handle) { |
| 708 callback.Run(ErrorTypeStorage); | 666 callback.Run(ErrorTypeStorage); |
| 709 return; | 667 return; |
| 710 } | 668 } |
| 711 } | 669 } |
| 712 | 670 |
| 713 ServiceWorkerFetchRequest* request_ptr = request.get(); | 671 base::Closure continuation = base::Bind(&ServiceWorkerCache::PutImpl, |
| 672 weak_ptr_factory_.GetWeakPtr(), |
| 673 base::Passed(request.Pass()), |
| 674 base::Passed(response.Pass()), |
| 675 base::Passed(blob_data_handle.Pass()), |
| 676 callback); |
| 714 | 677 |
| 715 net::CompletionCallback create_entry_callback = | 678 if (!initialized_) { |
| 716 base::Bind(PutDidCreateEntry, | 679 Init(continuation); |
| 717 base::Passed(request.Pass()), | 680 return; |
| 718 base::Passed(response.Pass()), | 681 } |
| 719 callback, | |
| 720 base::Passed(entry.Pass()), | |
| 721 base::Passed(blob_data_handle.Pass()), | |
| 722 request_context_); | |
| 723 | 682 |
| 724 int rv = backend_->CreateEntry( | 683 continuation.Run(); |
| 725 request_ptr->url.spec(), entry_ptr, create_entry_callback); | |
| 726 | |
| 727 if (rv != net::ERR_IO_PENDING) | |
| 728 create_entry_callback.Run(rv); | |
| 729 } | 684 } |
| 730 | 685 |
| 731 void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request, | 686 void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request, |
| 732 const ResponseCallback& callback) { | 687 const ResponseCallback& callback) { |
| 733 DCHECK(backend_); | 688 if (!initialized_) { |
| 689 Init(base::Bind(&ServiceWorkerCache::Match, |
| 690 weak_ptr_factory_.GetWeakPtr(), |
| 691 base::Passed(request.Pass()), |
| 692 callback)); |
| 693 return; |
| 694 } |
| 695 if (!backend_) { |
| 696 callback.Run(ErrorTypeStorage, |
| 697 scoped_ptr<ServiceWorkerResponse>(), |
| 698 scoped_ptr<storage::BlobDataHandle>()); |
| 699 return; |
| 700 } |
| 734 | 701 |
| 735 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); | 702 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
| 736 | 703 |
| 737 disk_cache::Entry** entry_ptr = entry.get(); | 704 disk_cache::Entry** entry_ptr = entry.get(); |
| 738 | 705 |
| 739 ServiceWorkerFetchRequest* request_ptr = request.get(); | 706 ServiceWorkerFetchRequest* request_ptr = request.get(); |
| 740 | 707 |
| 741 net::CompletionCallback open_entry_callback = | 708 net::CompletionCallback open_entry_callback = |
| 742 base::Bind(MatchDidOpenEntry, | 709 base::Bind(MatchDidOpenEntry, |
| 743 base::Passed(request.Pass()), | 710 base::Passed(request.Pass()), |
| 744 callback, | 711 callback, |
| 745 blob_storage_context_, | 712 blob_storage_context_, |
| 746 base::Passed(entry.Pass())); | 713 base::Passed(entry.Pass())); |
| 747 | 714 |
| 748 int rv = backend_->OpenEntry( | 715 int rv = backend_->OpenEntry( |
| 749 request_ptr->url.spec(), entry_ptr, open_entry_callback); | 716 request_ptr->url.spec(), entry_ptr, open_entry_callback); |
| 750 if (rv != net::ERR_IO_PENDING) | 717 if (rv != net::ERR_IO_PENDING) |
| 751 open_entry_callback.Run(rv); | 718 open_entry_callback.Run(rv); |
| 752 } | 719 } |
| 753 | 720 |
| 754 void ServiceWorkerCache::Delete(scoped_ptr<ServiceWorkerFetchRequest> request, | 721 void ServiceWorkerCache::Delete(scoped_ptr<ServiceWorkerFetchRequest> request, |
| 755 const ErrorCallback& callback) { | 722 const ErrorCallback& callback) { |
| 756 DCHECK(backend_); | 723 if (!initialized_) { |
| 724 Init(base::Bind(&ServiceWorkerCache::Delete, |
| 725 weak_ptr_factory_.GetWeakPtr(), |
| 726 base::Passed(request.Pass()), |
| 727 callback)); |
| 728 return; |
| 729 } |
| 730 if (!backend_) { |
| 731 callback.Run(ErrorTypeStorage); |
| 732 return; |
| 733 } |
| 757 | 734 |
| 758 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); | 735 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
| 759 | 736 |
| 760 disk_cache::Entry** entry_ptr = entry.get(); | 737 disk_cache::Entry** entry_ptr = entry.get(); |
| 761 | 738 |
| 762 ServiceWorkerFetchRequest* request_ptr = request.get(); | 739 ServiceWorkerFetchRequest* request_ptr = request.get(); |
| 763 | 740 |
| 764 net::CompletionCallback open_entry_callback = | 741 net::CompletionCallback open_entry_callback = |
| 765 base::Bind(DeleteDidOpenEntry, | 742 base::Bind(DeleteDidOpenEntry, |
| 766 base::Passed(request.Pass()), | 743 base::Passed(request.Pass()), |
| 767 callback, | 744 callback, |
| 768 base::Passed(entry.Pass())); | 745 base::Passed(entry.Pass())); |
| 769 | 746 |
| 770 int rv = backend_->OpenEntry( | 747 int rv = backend_->OpenEntry( |
| 771 request_ptr->url.spec(), entry_ptr, open_entry_callback); | 748 request_ptr->url.spec(), entry_ptr, open_entry_callback); |
| 772 if (rv != net::ERR_IO_PENDING) | 749 if (rv != net::ERR_IO_PENDING) |
| 773 open_entry_callback.Run(rv); | 750 open_entry_callback.Run(rv); |
| 774 } | 751 } |
| 775 | 752 |
| 776 void ServiceWorkerCache::Keys(const RequestsCallback& callback) { | 753 void ServiceWorkerCache::Keys(const RequestsCallback& callback) { |
| 777 DCHECK(backend_); | 754 if (!initialized_) { |
| 755 Init(base::Bind( |
| 756 &ServiceWorkerCache::Keys, weak_ptr_factory_.GetWeakPtr(), callback)); |
| 757 return; |
| 758 } |
| 759 if (!backend_) { |
| 760 callback.Run(ErrorTypeStorage, scoped_ptr<Requests>()); |
| 761 return; |
| 762 } |
| 778 | 763 |
| 779 // 1. Iterate through all of the entries, open them, and add them to a vector. | 764 // 1. Iterate through all of the entries, open them, and add them to a vector. |
| 780 // 2. For each open entry: | 765 // 2. For each open entry: |
| 781 // 2.1. Read the headers into a protobuf. | 766 // 2.1. Read the headers into a protobuf. |
| 782 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key"). | 767 // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key"). |
| 783 // 2.3. Push the response into a vector of requests to be returned. | 768 // 2.3. Push the response into a vector of requests to be returned. |
| 784 // 3. Return the vector of requests (keys). | 769 // 3. Return the vector of requests (keys). |
| 785 | 770 |
| 786 // The entries have to be loaded into a vector first because enumeration loops | 771 // The entries have to be loaded into a vector first because enumeration loops |
| 787 // forever if you read data from a cache entry while enumerating. | 772 // forever if you read data from a cache entry while enumerating. |
| 788 | 773 |
| 789 scoped_ptr<KeysContext> keys_context( | 774 scoped_ptr<KeysContext> keys_context( |
| 790 new KeysContext(callback, weak_ptr_factory_.GetWeakPtr())); | 775 new KeysContext(callback, weak_ptr_factory_.GetWeakPtr())); |
| 791 | 776 |
| 792 void** backend_iterator = &keys_context->backend_iterator; | 777 void** backend_iterator = &keys_context->backend_iterator; |
| 793 disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry; | 778 disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry; |
| 794 | 779 |
| 795 net::CompletionCallback open_entry_callback = | 780 net::CompletionCallback open_entry_callback = |
| 796 base::Bind(KeysDidOpenNextEntry, base::Passed(keys_context.Pass())); | 781 base::Bind(KeysDidOpenNextEntry, base::Passed(keys_context.Pass())); |
| 797 | 782 |
| 798 int rv = backend_->OpenNextEntry( | 783 int rv = backend_->OpenNextEntry( |
| 799 backend_iterator, enumerated_entry, open_entry_callback); | 784 backend_iterator, enumerated_entry, open_entry_callback); |
| 800 | 785 |
| 801 if (rv != net::ERR_IO_PENDING) | 786 if (rv != net::ERR_IO_PENDING) |
| 802 open_entry_callback.Run(rv); | 787 open_entry_callback.Run(rv); |
| 803 } | 788 } |
| 804 | 789 |
| 805 bool ServiceWorkerCache::HasCreatedBackend() const { | |
| 806 return backend_; | |
| 807 } | |
| 808 | |
| 809 ServiceWorkerCache::ServiceWorkerCache( | 790 ServiceWorkerCache::ServiceWorkerCache( |
| 810 const base::FilePath& path, | 791 const base::FilePath& path, |
| 811 net::URLRequestContext* request_context, | 792 net::URLRequestContext* request_context, |
| 812 base::WeakPtr<storage::BlobStorageContext> blob_context) | 793 base::WeakPtr<storage::BlobStorageContext> blob_context) |
| 813 : path_(path), | 794 : path_(path), |
| 814 request_context_(request_context), | 795 request_context_(request_context), |
| 815 blob_storage_context_(blob_context), | 796 blob_storage_context_(blob_context), |
| 797 initialized_(false), |
| 816 weak_ptr_factory_(this) { | 798 weak_ptr_factory_(this) { |
| 817 } | 799 } |
| 818 | 800 |
| 801 void ServiceWorkerCache::PutImpl( |
| 802 scoped_ptr<ServiceWorkerFetchRequest> request, |
| 803 scoped_ptr<ServiceWorkerResponse> response, |
| 804 scoped_ptr<storage::BlobDataHandle> blob_data_handle, |
| 805 const ErrorCallback& callback) { |
| 806 if (!backend_) { |
| 807 callback.Run(ErrorTypeStorage); |
| 808 return; |
| 809 } |
| 810 |
| 811 scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*); |
| 812 |
| 813 disk_cache::Entry** entry_ptr = entry.get(); |
| 814 |
| 815 ServiceWorkerFetchRequest* request_ptr = request.get(); |
| 816 |
| 817 net::CompletionCallback create_entry_callback = |
| 818 base::Bind(PutDidCreateEntry, |
| 819 base::Passed(request.Pass()), |
| 820 base::Passed(response.Pass()), |
| 821 callback, |
| 822 base::Passed(entry.Pass()), |
| 823 base::Passed(blob_data_handle.Pass()), |
| 824 request_context_); |
| 825 |
| 826 int rv = backend_->CreateEntry( |
| 827 request_ptr->url.spec(), entry_ptr, create_entry_callback); |
| 828 |
| 829 if (rv != net::ERR_IO_PENDING) |
| 830 create_entry_callback.Run(rv); |
| 831 } |
| 832 |
| 819 // static | 833 // static |
| 820 void ServiceWorkerCache::KeysDidOpenNextEntry( | 834 void ServiceWorkerCache::KeysDidOpenNextEntry( |
| 821 scoped_ptr<KeysContext> keys_context, | 835 scoped_ptr<KeysContext> keys_context, |
| 822 int rv) { | 836 int rv) { |
| 823 if (rv == net::ERR_FAILED) { | 837 if (rv == net::ERR_FAILED) { |
| 824 DCHECK(!keys_context->enumerated_entry); | 838 DCHECK(!keys_context->enumerated_entry); |
| 825 // Enumeration is complete, extract the requests from the entries. | 839 // Enumeration is complete, extract the requests from the entries. |
| 826 Entries::iterator iter = keys_context->entries.begin(); | 840 Entries::iterator iter = keys_context->entries.begin(); |
| 827 KeysProcessNextEntry(keys_context.Pass(), iter); | 841 KeysProcessNextEntry(keys_context.Pass(), iter); |
| 828 return; | 842 return; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 headers->request_headers(i); | 906 headers->request_headers(i); |
| 893 req_headers.insert(std::make_pair(header.name(), header.value())); | 907 req_headers.insert(std::make_pair(header.name(), header.value())); |
| 894 } | 908 } |
| 895 } else { | 909 } else { |
| 896 entry->Doom(); | 910 entry->Doom(); |
| 897 } | 911 } |
| 898 | 912 |
| 899 KeysProcessNextEntry(keys_context.Pass(), iter + 1); | 913 KeysProcessNextEntry(keys_context.Pass(), iter + 1); |
| 900 } | 914 } |
| 901 | 915 |
| 916 void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) { |
| 917 DCHECK(!backend_); |
| 918 |
| 919 // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction. |
| 920 net::CacheType cache_type = |
| 921 path_.empty() ? net::MEMORY_CACHE : net::APP_CACHE; |
| 922 |
| 923 scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr()); |
| 924 |
| 925 // Temporary pointer so that backend_ptr can be Pass()'d in Bind below. |
| 926 ScopedBackendPtr* backend = backend_ptr.get(); |
| 927 |
| 928 net::CompletionCallback create_cache_callback = |
| 929 base::Bind(CreateBackendDidCreate, |
| 930 callback, |
| 931 base::Passed(backend_ptr.Pass()), |
| 932 weak_ptr_factory_.GetWeakPtr()); |
| 933 |
| 934 // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore |
| 935 // has for disk caches. |
| 936 int rv = disk_cache::CreateCacheBackend( |
| 937 cache_type, |
| 938 net::CACHE_BACKEND_SIMPLE, |
| 939 path_, |
| 940 kMaxCacheBytes, |
| 941 false, /* force */ |
| 942 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(), |
| 943 NULL, |
| 944 backend, |
| 945 create_cache_callback); |
| 946 if (rv != net::ERR_IO_PENDING) |
| 947 create_cache_callback.Run(rv); |
| 948 } |
| 949 |
| 950 void ServiceWorkerCache::Init(const base::Closure& callback) { |
| 951 init_callbacks_.push_back(callback); |
| 952 |
| 953 // If this isn't the first call to Init then return as the initialization |
| 954 // has already started. |
| 955 if (init_callbacks_.size() > 1u) |
| 956 return; |
| 957 |
| 958 CreateBackend(base::Bind(&ServiceWorkerCache::InitDone, |
| 959 weak_ptr_factory_.GetWeakPtr())); |
| 960 } |
| 961 |
| 962 void ServiceWorkerCache::InitDone(ErrorType error) { |
| 963 initialized_ = true; |
| 964 for (std::vector<base::Closure>::iterator it = init_callbacks_.begin(); |
| 965 it != init_callbacks_.end(); |
| 966 ++it) { |
| 967 it->Run(); |
| 968 } |
| 969 init_callbacks_.clear(); |
| 970 } |
| 971 |
| 902 } // namespace content | 972 } // namespace content |
| OLD | NEW |