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
3 // found in the LICENSE file.
5 #include "content/browser/service_worker/service_worker_cache_listener.h"
8 #include "base/debug/trace_event.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/service_worker/service_worker_cache.h"
11 #include "content/browser/service_worker/service_worker_cache_storage_manager.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_version.h"
14 #include "content/common/service_worker/service_worker_messages.h"
15 #include "storage/browser/blob/blob_data_handle.h"
16 #include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
20 using blink::WebServiceWorkerCacheError;
24 WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
25 ServiceWorkerCacheStorage::CacheStorageError err) {
27 case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR:
29 return blink::WebServiceWorkerCacheErrorNotImplemented;
30 case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_IMPLEMENTED:
31 return blink::WebServiceWorkerCacheErrorNotImplemented;
32 case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND:
33 return blink::WebServiceWorkerCacheErrorNotFound;
34 case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EXISTS:
35 return blink::WebServiceWorkerCacheErrorExists;
36 case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_STORAGE:
37 // TODO(jkarlin): Change this to CACHE_STORAGE_ERROR_STORAGE once that's
39 return blink::WebServiceWorkerCacheErrorNotFound;
40 case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_CLOSING:
41 // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_CLOSING once that's
43 return blink::WebServiceWorkerCacheErrorNotFound;
46 return blink::WebServiceWorkerCacheErrorNotImplemented;
49 // TODO(jkarlin): ServiceWorkerCache and ServiceWorkerCacheStorage should share
50 // an error enum type.
51 WebServiceWorkerCacheError CacheErrorToWebServiceWorkerCacheError(
52 ServiceWorkerCache::ErrorType err) {
54 case ServiceWorkerCache::ErrorTypeOK:
56 return blink::WebServiceWorkerCacheErrorNotImplemented;
57 case ServiceWorkerCache::ErrorTypeExists:
58 return blink::WebServiceWorkerCacheErrorExists;
59 case ServiceWorkerCache::ErrorTypeStorage:
60 // TODO(jkarlin): Change this to CACHE_STORAGE_ERROR_STORAGE once that's
62 return blink::WebServiceWorkerCacheErrorNotFound;
63 case ServiceWorkerCache::ErrorTypeNotFound:
64 return blink::WebServiceWorkerCacheErrorNotFound;
67 return blink::WebServiceWorkerCacheErrorNotImplemented;
72 ServiceWorkerCacheListener::ServiceWorkerCacheListener(
73 ServiceWorkerVersion* version,
74 base::WeakPtr<ServiceWorkerContextCore> context)
79 version_->embedded_worker()->AddListener(this);
82 ServiceWorkerCacheListener::~ServiceWorkerCacheListener() {
83 version_->embedded_worker()->RemoveListener(this);
86 bool ServiceWorkerCacheListener::OnMessageReceived(
87 const IPC::Message& message) {
89 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerCacheListener, message)
90 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageHas,
92 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageOpen,
94 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageDelete,
96 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageKeys,
98 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheMatch,
100 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheMatchAll,
102 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheKeys,
104 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheBatch,
106 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheClosed,
108 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_BlobDataHandled, OnBlobDataHandled)
109 IPC_MESSAGE_UNHANDLED(handled = false)
110 IPC_END_MESSAGE_MAP()
115 void ServiceWorkerCacheListener::OnCacheStorageHas(
117 const base::string16& cache_name) {
118 TRACE_EVENT0("ServiceWorker",
119 "ServiceWorkerCacheListener::OnCacheStorageHas");
120 context_->cache_manager()->HasCache(
121 version_->scope().GetOrigin(),
122 base::UTF16ToUTF8(cache_name),
123 base::Bind(&ServiceWorkerCacheListener::OnCacheStorageHasCallback,
124 weak_factory_.GetWeakPtr(),
128 void ServiceWorkerCacheListener::OnCacheStorageOpen(
130 const base::string16& cache_name) {
131 TRACE_EVENT0("ServiceWorker",
132 "ServiceWorkerCacheListener::OnCacheStorageOpen");
133 context_->cache_manager()->OpenCache(
134 version_->scope().GetOrigin(),
135 base::UTF16ToUTF8(cache_name),
136 base::Bind(&ServiceWorkerCacheListener::OnCacheStorageOpenCallback,
137 weak_factory_.GetWeakPtr(),
141 void ServiceWorkerCacheListener::OnCacheStorageDelete(
143 const base::string16& cache_name) {
144 TRACE_EVENT0("ServiceWorker",
145 "ServiceWorkerCacheListener::OnCacheStorageDelete");
146 context_->cache_manager()->DeleteCache(
147 version_->scope().GetOrigin(),
148 base::UTF16ToUTF8(cache_name),
149 base::Bind(&ServiceWorkerCacheListener::OnCacheStorageDeleteCallback,
150 weak_factory_.GetWeakPtr(),
154 void ServiceWorkerCacheListener::OnCacheStorageKeys(int request_id) {
155 TRACE_EVENT0("ServiceWorker",
156 "ServiceWorkerCacheListener::OnCacheStorageKeys");
157 context_->cache_manager()->EnumerateCaches(
158 version_->scope().GetOrigin(),
159 base::Bind(&ServiceWorkerCacheListener::OnCacheStorageKeysCallback,
160 weak_factory_.GetWeakPtr(),
164 void ServiceWorkerCacheListener::OnCacheMatch(
167 const ServiceWorkerFetchRequest& request,
168 const ServiceWorkerCacheQueryParams& match_params) {
169 IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
170 if (it == id_to_cache_map_.end()) {
171 Send(ServiceWorkerMsg_CacheMatchError(
172 request_id, blink::WebServiceWorkerCacheErrorNotFound));
176 scoped_refptr<ServiceWorkerCache> cache = it->second;
177 scoped_ptr<ServiceWorkerFetchRequest> scoped_request(
178 new ServiceWorkerFetchRequest(request.url,
183 cache->Match(scoped_request.Pass(),
184 base::Bind(&ServiceWorkerCacheListener::OnCacheMatchCallback,
185 weak_factory_.GetWeakPtr(),
190 void ServiceWorkerCacheListener::OnCacheMatchAll(
193 const ServiceWorkerFetchRequest& request,
194 const ServiceWorkerCacheQueryParams& match_params) {
195 // TODO(gavinp,jkarlin): Implement this method.
196 Send(ServiceWorkerMsg_CacheMatchAllError(
197 request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
200 void ServiceWorkerCacheListener::OnCacheKeys(
203 const ServiceWorkerFetchRequest& request,
204 const ServiceWorkerCacheQueryParams& match_params) {
205 IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
206 if (it == id_to_cache_map_.end()) {
207 Send(ServiceWorkerMsg_CacheKeysError(
208 request_id, blink::WebServiceWorkerCacheErrorNotFound));
212 scoped_refptr<ServiceWorkerCache> cache = it->second;
214 cache->Keys(base::Bind(&ServiceWorkerCacheListener::OnCacheKeysCallback,
215 weak_factory_.GetWeakPtr(),
220 void ServiceWorkerCacheListener::OnCacheBatch(
223 const std::vector<ServiceWorkerBatchOperation>& operations) {
224 if (operations.size() != 1u) {
225 Send(ServiceWorkerMsg_CacheBatchError(
226 request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
230 IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
231 if (it == id_to_cache_map_.end()) {
232 Send(ServiceWorkerMsg_CacheBatchError(
233 request_id, blink::WebServiceWorkerCacheErrorNotFound));
237 const ServiceWorkerBatchOperation& operation = operations[0];
239 scoped_refptr<ServiceWorkerCache> cache = it->second;
240 scoped_ptr<ServiceWorkerFetchRequest> scoped_request(
241 new ServiceWorkerFetchRequest(operation.request.url,
242 operation.request.method,
243 operation.request.headers,
244 operation.request.referrer,
245 operation.request.is_reload));
247 if (operation.operation_type == SERVICE_WORKER_CACHE_OPERATION_TYPE_DELETE) {
248 cache->Delete(scoped_request.Pass(),
249 base::Bind(&ServiceWorkerCacheListener::OnCacheDeleteCallback,
250 weak_factory_.GetWeakPtr(),
256 if (operation.operation_type == SERVICE_WORKER_CACHE_OPERATION_TYPE_PUT) {
257 scoped_ptr<ServiceWorkerResponse> scoped_response(
258 new ServiceWorkerResponse(operation.response.url,
259 operation.response.status_code,
260 operation.response.status_text,
261 operation.response.response_type,
262 operation.response.headers,
263 operation.response.blob_uuid,
264 operation.response.blob_size));
265 cache->Put(scoped_request.Pass(),
266 scoped_response.Pass(),
267 base::Bind(&ServiceWorkerCacheListener::OnCachePutCallback,
268 weak_factory_.GetWeakPtr(),
275 Send(ServiceWorkerMsg_CacheBatchError(
276 request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
279 void ServiceWorkerCacheListener::OnCacheClosed(int cache_id) {
280 DropCacheReference(cache_id);
283 void ServiceWorkerCacheListener::OnBlobDataHandled(const std::string& uuid) {
284 DropBlobDataHandle(uuid);
287 void ServiceWorkerCacheListener::Send(const IPC::Message& message) {
288 version_->embedded_worker()->SendMessage(message);
291 void ServiceWorkerCacheListener::OnCacheStorageHasCallback(
294 ServiceWorkerCacheStorage::CacheStorageError error) {
295 if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
296 Send(ServiceWorkerMsg_CacheStorageHasError(
297 request_id, ToWebServiceWorkerCacheError(error)));
301 Send(ServiceWorkerMsg_CacheStorageHasError(
303 blink::WebServiceWorkerCacheErrorNotFound));
306 Send(ServiceWorkerMsg_CacheStorageHasSuccess(request_id));
309 void ServiceWorkerCacheListener::OnCacheStorageOpenCallback(
311 const scoped_refptr<ServiceWorkerCache>& cache,
312 ServiceWorkerCacheStorage::CacheStorageError error) {
313 if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
314 Send(ServiceWorkerMsg_CacheStorageOpenError(
315 request_id, ToWebServiceWorkerCacheError(error)));
318 CacheID cache_id = StoreCacheReference(cache);
319 Send(ServiceWorkerMsg_CacheStorageOpenSuccess(request_id, cache_id));
322 void ServiceWorkerCacheListener::OnCacheStorageDeleteCallback(
325 ServiceWorkerCacheStorage::CacheStorageError error) {
327 error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
328 Send(ServiceWorkerMsg_CacheStorageDeleteError(
329 request_id, ToWebServiceWorkerCacheError(error)));
332 Send(ServiceWorkerMsg_CacheStorageDeleteSuccess(request_id));
335 void ServiceWorkerCacheListener::OnCacheStorageKeysCallback(
337 const std::vector<std::string>& strings,
338 ServiceWorkerCacheStorage::CacheStorageError error) {
339 if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
340 Send(ServiceWorkerMsg_CacheStorageKeysError(
341 request_id, ToWebServiceWorkerCacheError(error)));
345 std::vector<base::string16> string16s;
346 for (size_t i = 0, max = strings.size(); i < max; ++i) {
347 string16s.push_back(base::UTF8ToUTF16(strings[i]));
349 Send(ServiceWorkerMsg_CacheStorageKeysSuccess(request_id, string16s));
352 void ServiceWorkerCacheListener::OnCacheMatchCallback(
354 const scoped_refptr<ServiceWorkerCache>& cache,
355 ServiceWorkerCache::ErrorType error,
356 scoped_ptr<ServiceWorkerResponse> response,
357 scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
358 if (error != ServiceWorkerCache::ErrorTypeOK) {
359 Send(ServiceWorkerMsg_CacheMatchError(
360 request_id, CacheErrorToWebServiceWorkerCacheError(error)));
364 if (blob_data_handle)
365 StoreBlobDataHandle(blob_data_handle.Pass());
367 Send(ServiceWorkerMsg_CacheMatchSuccess(request_id, *response));
370 void ServiceWorkerCacheListener::OnCacheKeysCallback(
372 const scoped_refptr<ServiceWorkerCache>& cache,
373 ServiceWorkerCache::ErrorType error,
374 scoped_ptr<ServiceWorkerCache::Requests> requests) {
375 if (error != ServiceWorkerCache::ErrorTypeOK) {
376 Send(ServiceWorkerMsg_CacheKeysError(
377 request_id, CacheErrorToWebServiceWorkerCacheError(error)));
381 ServiceWorkerCache::Requests out;
383 for (ServiceWorkerCache::Requests::const_iterator it = requests->begin();
384 it != requests->end();
386 ServiceWorkerFetchRequest request(
387 it->url, it->method, it->headers, it->referrer, it->is_reload);
388 out.push_back(request);
391 Send(ServiceWorkerMsg_CacheKeysSuccess(request_id, out));
394 void ServiceWorkerCacheListener::OnCacheDeleteCallback(
396 const scoped_refptr<ServiceWorkerCache>& cache,
397 ServiceWorkerCache::ErrorType error) {
398 if (error != ServiceWorkerCache::ErrorTypeOK) {
399 Send(ServiceWorkerMsg_CacheBatchError(
400 request_id, CacheErrorToWebServiceWorkerCacheError(error)));
404 Send(ServiceWorkerMsg_CacheBatchSuccess(
405 request_id, std::vector<ServiceWorkerResponse>()));
408 void ServiceWorkerCacheListener::OnCachePutCallback(
410 const scoped_refptr<ServiceWorkerCache>& cache,
411 ServiceWorkerCache::ErrorType error,
412 scoped_ptr<ServiceWorkerResponse> response,
413 scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
414 if (error != ServiceWorkerCache::ErrorTypeOK) {
415 Send(ServiceWorkerMsg_CacheBatchError(
416 request_id, CacheErrorToWebServiceWorkerCacheError(error)));
420 if (blob_data_handle)
421 StoreBlobDataHandle(blob_data_handle.Pass());
423 std::vector<ServiceWorkerResponse> responses;
424 responses.push_back(*response);
425 Send(ServiceWorkerMsg_CacheBatchSuccess(request_id, responses));
428 ServiceWorkerCacheListener::CacheID
429 ServiceWorkerCacheListener::StoreCacheReference(
430 const scoped_refptr<ServiceWorkerCache>& cache) {
431 int cache_id = next_cache_id_++;
432 id_to_cache_map_[cache_id] = cache;
436 void ServiceWorkerCacheListener::DropCacheReference(CacheID cache_id) {
437 id_to_cache_map_.erase(cache_id);
440 void ServiceWorkerCacheListener::StoreBlobDataHandle(
441 scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
442 DCHECK(blob_data_handle);
443 std::pair<UUIDToBlobDataHandleList::iterator, bool> rv =
444 blob_handle_store_.insert(std::make_pair(
445 blob_data_handle->uuid(), std::list<storage::BlobDataHandle>()));
446 rv.first->second.push_front(storage::BlobDataHandle(*blob_data_handle));
449 void ServiceWorkerCacheListener::DropBlobDataHandle(std::string uuid) {
450 UUIDToBlobDataHandleList::iterator it = blob_handle_store_.find(uuid);
451 if (it == blob_handle_store_.end())
453 DCHECK(!it->second.empty());
454 it->second.pop_front();
455 if (it->second.empty())
456 blob_handle_store_.erase(it);
459 } // namespace content