OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_storage.h" | 5 #include "content/browser/service_worker/service_worker_storage.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
12 #include "base/sequenced_task_runner.h" | 12 #include "base/sequenced_task_runner.h" |
13 #include "base/task_runner_util.h" | 13 #include "base/task_runner_util.h" |
14 #include "content/browser/service_worker/service_worker_context_core.h" | 14 #include "content/browser/service_worker/service_worker_context_core.h" |
15 #include "content/browser/service_worker/service_worker_disk_cache.h" | 15 #include "content/browser/service_worker/service_worker_disk_cache.h" |
16 #include "content/browser/service_worker/service_worker_info.h" | 16 #include "content/browser/service_worker/service_worker_info.h" |
17 #include "content/browser/service_worker/service_worker_metrics.h" | 17 #include "content/browser/service_worker/service_worker_metrics.h" |
18 #include "content/browser/service_worker/service_worker_registration.h" | 18 #include "content/browser/service_worker/service_worker_registration.h" |
19 #include "content/browser/service_worker/service_worker_utils.h" | 19 #include "content/browser/service_worker/service_worker_utils.h" |
20 #include "content/browser/service_worker/service_worker_version.h" | 20 #include "content/browser/service_worker/service_worker_version.h" |
21 #include "content/common/service_worker/service_worker_types.h" | 21 #include "content/common/service_worker/service_worker_types.h" |
22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
23 #include "net/base/completion_callback.h" | 23 #include "net/base/completion_callback.h" |
| 24 #include "net/base/io_buffer.h" |
24 #include "net/base/net_errors.h" | 25 #include "net/base/net_errors.h" |
25 #include "webkit/browser/quota/quota_manager_proxy.h" | 26 #include "webkit/browser/quota/quota_manager_proxy.h" |
26 | 27 |
27 namespace content { | 28 namespace content { |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 void RunSoon(const tracked_objects::Location& from_here, | 32 void RunSoon(const tracked_objects::Location& from_here, |
32 const base::Closure& closure) { | 33 const base::Closure& closure) { |
33 base::MessageLoop::current()->PostTask(from_here, closure); | 34 base::MessageLoop::current()->PostTask(from_here, closure); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 return SERVICE_WORKER_OK; | 66 return SERVICE_WORKER_OK; |
66 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND: | 67 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND: |
67 return SERVICE_WORKER_ERROR_NOT_FOUND; | 68 return SERVICE_WORKER_ERROR_NOT_FOUND; |
68 case ServiceWorkerDatabase::STATUS_ERROR_MAX: | 69 case ServiceWorkerDatabase::STATUS_ERROR_MAX: |
69 NOTREACHED(); | 70 NOTREACHED(); |
70 default: | 71 default: |
71 return SERVICE_WORKER_ERROR_FAILED; | 72 return SERVICE_WORKER_ERROR_FAILED; |
72 } | 73 } |
73 } | 74 } |
74 | 75 |
| 76 class ResponseComparer : public base::RefCounted<ResponseComparer> { |
| 77 public: |
| 78 ResponseComparer( |
| 79 base::WeakPtr<ServiceWorkerStorage> owner, |
| 80 scoped_ptr<ServiceWorkerResponseReader> lhs, |
| 81 scoped_ptr<ServiceWorkerResponseReader> rhs, |
| 82 const ServiceWorkerStorage::CompareCallback& callback) |
| 83 : owner_(owner), |
| 84 completion_callback_(callback), |
| 85 lhs_reader_(lhs.release()), |
| 86 rhs_reader_(rhs.release()), |
| 87 completion_count_(0), |
| 88 previous_result_(0) { |
| 89 } |
| 90 |
| 91 void Start(); |
| 92 |
| 93 private: |
| 94 friend class base::RefCounted<ResponseComparer>; |
| 95 |
| 96 static const int kBufferSize = 16 * 1024; |
| 97 |
| 98 ~ResponseComparer() {} |
| 99 void ReadInfos(); |
| 100 void OnReadInfoComplete(int result); |
| 101 void ReadSomeData(); |
| 102 void OnReadDataComplete(int result); |
| 103 |
| 104 base::WeakPtr<ServiceWorkerStorage> owner_; |
| 105 ServiceWorkerStorage::CompareCallback completion_callback_; |
| 106 scoped_ptr<ServiceWorkerResponseReader> lhs_reader_; |
| 107 scoped_refptr<HttpResponseInfoIOBuffer> lhs_info_; |
| 108 scoped_refptr<net::IOBuffer> lhs_buffer_; |
| 109 scoped_ptr<ServiceWorkerResponseReader> rhs_reader_; |
| 110 scoped_refptr<HttpResponseInfoIOBuffer> rhs_info_; |
| 111 scoped_refptr<net::IOBuffer> rhs_buffer_; |
| 112 int completion_count_; |
| 113 int previous_result_; |
| 114 DISALLOW_COPY_AND_ASSIGN(ResponseComparer); |
| 115 }; |
| 116 |
| 117 void ResponseComparer::Start() { |
| 118 lhs_buffer_ = new net::IOBuffer(kBufferSize); |
| 119 lhs_info_ = new HttpResponseInfoIOBuffer(); |
| 120 rhs_buffer_ = new net::IOBuffer(kBufferSize); |
| 121 rhs_info_ = new HttpResponseInfoIOBuffer(); |
| 122 |
| 123 ReadInfos(); |
| 124 } |
| 125 |
| 126 void ResponseComparer::ReadInfos() { |
| 127 lhs_reader_->ReadInfo( |
| 128 lhs_info_, |
| 129 base::Bind(&ResponseComparer::OnReadInfoComplete, |
| 130 this)); |
| 131 rhs_reader_->ReadInfo( |
| 132 rhs_info_, |
| 133 base::Bind(&ResponseComparer::OnReadInfoComplete, |
| 134 this)); |
| 135 } |
| 136 |
| 137 void ResponseComparer::OnReadInfoComplete(int result) { |
| 138 if (completion_callback_.is_null() || !owner_) |
| 139 return; |
| 140 if (result < 0) { |
| 141 completion_callback_.Run(SERVICE_WORKER_ERROR_FAILED, false); |
| 142 completion_callback_.Reset(); |
| 143 return; |
| 144 } |
| 145 if (++completion_count_ != 2) |
| 146 return; |
| 147 |
| 148 if (lhs_info_->response_data_size != rhs_info_->response_data_size) { |
| 149 completion_callback_.Run(SERVICE_WORKER_OK, false); |
| 150 return; |
| 151 } |
| 152 ReadSomeData(); |
| 153 } |
| 154 |
| 155 void ResponseComparer::ReadSomeData() { |
| 156 completion_count_ = 0; |
| 157 lhs_reader_->ReadData( |
| 158 lhs_buffer_, |
| 159 kBufferSize, |
| 160 base::Bind(&ResponseComparer::OnReadDataComplete, this)); |
| 161 rhs_reader_->ReadData( |
| 162 rhs_buffer_, |
| 163 kBufferSize, |
| 164 base::Bind(&ResponseComparer::OnReadDataComplete, this)); |
| 165 } |
| 166 |
| 167 void ResponseComparer::OnReadDataComplete(int result) { |
| 168 if (completion_callback_.is_null() || !owner_) |
| 169 return; |
| 170 if (result < 0) { |
| 171 completion_callback_.Run(SERVICE_WORKER_ERROR_FAILED, false); |
| 172 completion_callback_.Reset(); |
| 173 return; |
| 174 } |
| 175 if (++completion_count_ != 2) { |
| 176 previous_result_ = result; |
| 177 return; |
| 178 } |
| 179 |
| 180 // TODO(michaeln): Probably shouldn't assume that the amounts read from |
| 181 // each reader will always be the same. This would wrongly signal false |
| 182 // in that case. |
| 183 if (result != previous_result_) { |
| 184 completion_callback_.Run(SERVICE_WORKER_OK, false); |
| 185 return; |
| 186 } |
| 187 |
| 188 if (result == 0) { |
| 189 completion_callback_.Run(SERVICE_WORKER_OK, true); |
| 190 return; |
| 191 } |
| 192 |
| 193 int compare_result = |
| 194 memcmp(lhs_buffer_->data(), rhs_buffer_->data(), result); |
| 195 if (compare_result != 0) { |
| 196 completion_callback_.Run(SERVICE_WORKER_OK, false); |
| 197 return; |
| 198 } |
| 199 |
| 200 ReadSomeData(); |
| 201 } |
| 202 |
75 } // namespace | 203 } // namespace |
76 | 204 |
77 ServiceWorkerStorage::InitialData::InitialData() | 205 ServiceWorkerStorage::InitialData::InitialData() |
78 : next_registration_id(kInvalidServiceWorkerRegistrationId), | 206 : next_registration_id(kInvalidServiceWorkerRegistrationId), |
79 next_version_id(kInvalidServiceWorkerVersionId), | 207 next_version_id(kInvalidServiceWorkerVersionId), |
80 next_resource_id(kInvalidServiceWorkerResourceId) { | 208 next_resource_id(kInvalidServiceWorkerResourceId) { |
81 } | 209 } |
82 | 210 |
83 ServiceWorkerStorage::InitialData::~InitialData() { | 211 ServiceWorkerStorage::InitialData::~InitialData() { |
84 } | 212 } |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 DCHECK_NE(kInvalidServiceWorkerResponseId, id); | 512 DCHECK_NE(kInvalidServiceWorkerResponseId, id); |
385 database_task_runner_->PostTask( | 513 database_task_runner_->PostTask( |
386 FROM_HERE, | 514 FROM_HERE, |
387 base::Bind(base::IgnoreResult( | 515 base::Bind(base::IgnoreResult( |
388 &ServiceWorkerDatabase::PurgeUncommittedResourceIds), | 516 &ServiceWorkerDatabase::PurgeUncommittedResourceIds), |
389 base::Unretained(database_.get()), | 517 base::Unretained(database_.get()), |
390 std::set<int64>(&id, &id + 1))); | 518 std::set<int64>(&id, &id + 1))); |
391 StartPurgingResources(std::vector<int64>(1, id)); | 519 StartPurgingResources(std::vector<int64>(1, id)); |
392 } | 520 } |
393 | 521 |
| 522 void ServiceWorkerStorage::CompareScriptResources( |
| 523 int64 lhs_id, int64 rhs_id, |
| 524 const CompareCallback& callback) { |
| 525 DCHECK(!callback.is_null()); |
| 526 scoped_refptr<ResponseComparer> comparer = |
| 527 new ResponseComparer(weak_factory_.GetWeakPtr(), |
| 528 CreateResponseReader(lhs_id), |
| 529 CreateResponseReader(rhs_id), |
| 530 callback); |
| 531 comparer->Start(); // It deletes itself when done. |
| 532 } |
| 533 |
394 void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback& callback) { | 534 void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback& callback) { |
395 Disable(); | 535 Disable(); |
396 | 536 |
397 // Delete the database on the database thread. | 537 // Delete the database on the database thread. |
398 PostTaskAndReplyWithResult( | 538 PostTaskAndReplyWithResult( |
399 database_task_runner_, | 539 database_task_runner_, |
400 FROM_HERE, | 540 FROM_HERE, |
401 base::Bind(&ServiceWorkerDatabase::DestroyDatabase, | 541 base::Bind(&ServiceWorkerDatabase::DestroyDatabase, |
402 base::Unretained(database_.get())), | 542 base::Unretained(database_.get())), |
403 base::Bind(&ServiceWorkerStorage::DidDeleteDatabase, | 543 base::Bind(&ServiceWorkerStorage::DidDeleteDatabase, |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 | 893 |
754 registration = new ServiceWorkerRegistration( | 894 registration = new ServiceWorkerRegistration( |
755 data.scope, data.script, data.registration_id, context_); | 895 data.scope, data.script, data.registration_id, context_); |
756 scoped_refptr<ServiceWorkerVersion> version = | 896 scoped_refptr<ServiceWorkerVersion> version = |
757 context_->GetLiveVersion(data.version_id); | 897 context_->GetLiveVersion(data.version_id); |
758 if (!version) { | 898 if (!version) { |
759 version = new ServiceWorkerVersion(registration, data.version_id, context_); | 899 version = new ServiceWorkerVersion(registration, data.version_id, context_); |
760 version->SetStatus(data.is_active ? | 900 version->SetStatus(data.is_active ? |
761 ServiceWorkerVersion::ACTIVATED : ServiceWorkerVersion::INSTALLED); | 901 ServiceWorkerVersion::ACTIVATED : ServiceWorkerVersion::INSTALLED); |
762 version->script_cache_map()->SetResources(resources); | 902 version->script_cache_map()->SetResources(resources); |
| 903 |
| 904 // TODO(michaeln): need to activate a waiting version that wasn't |
| 905 // actrivated in an earlier session, maybe test for this condition |
| 906 // (waitingversion and no activeversion) when navigating to a page? |
763 } | 907 } |
764 | 908 |
765 if (version->status() == ServiceWorkerVersion::ACTIVATED) | 909 if (version->status() == ServiceWorkerVersion::ACTIVATED) |
766 registration->SetActiveVersion(version); | 910 registration->SetActiveVersion(version); |
767 else if (version->status() == ServiceWorkerVersion::INSTALLED) | 911 else if (version->status() == ServiceWorkerVersion::INSTALLED) |
768 registration->SetWaitingVersion(version); | 912 registration->SetWaitingVersion(version); |
769 else | 913 else |
770 NOTREACHED(); | 914 NOTREACHED(); |
771 // TODO(michaeln): Hmmm, what if DeleteReg was invoked after | 915 |
772 // the Find result we're returning here? NOTREACHED condition? | |
773 return registration; | 916 return registration; |
774 } | 917 } |
775 | 918 |
776 ServiceWorkerRegistration* | 919 ServiceWorkerRegistration* |
777 ServiceWorkerStorage::FindInstallingRegistrationForDocument( | 920 ServiceWorkerStorage::FindInstallingRegistrationForDocument( |
778 const GURL& document_url) { | 921 const GURL& document_url) { |
779 DCHECK(!document_url.has_ref()); | 922 DCHECK(!document_url.has_ref()); |
780 | 923 |
781 LongestScopeMatcher matcher(document_url); | 924 LongestScopeMatcher matcher(document_url); |
782 ServiceWorkerRegistration* match = NULL; | 925 ServiceWorkerRegistration* match = NULL; |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 // Give up the corruption recovery until the browser restarts. | 1317 // Give up the corruption recovery until the browser restarts. |
1175 LOG(ERROR) << "Failed to delete the diskcache."; | 1318 LOG(ERROR) << "Failed to delete the diskcache."; |
1176 callback.Run(SERVICE_WORKER_ERROR_FAILED); | 1319 callback.Run(SERVICE_WORKER_ERROR_FAILED); |
1177 return; | 1320 return; |
1178 } | 1321 } |
1179 DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully."; | 1322 DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully."; |
1180 callback.Run(SERVICE_WORKER_OK); | 1323 callback.Run(SERVICE_WORKER_OK); |
1181 } | 1324 } |
1182 | 1325 |
1183 } // namespace content | 1326 } // namespace content |
OLD | NEW |