Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_cache_listener.cc
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.
4
5 #include "content/browser/service_worker/service_worker_cache_listener.h"
6
7 #include "base/bind.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"
17
18 namespace content {
19
20 using blink::WebServiceWorkerCacheError;
21
22 namespace {
23
24 WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
25     ServiceWorkerCacheStorage::CacheStorageError err) {
26   switch (err) {
27     case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR:
28       NOTREACHED();
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
38       // added.
39       return blink::WebServiceWorkerCacheErrorNotFound;
40     case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_CLOSING:
41       // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_CLOSING once that's
42       // added.
43       return blink::WebServiceWorkerCacheErrorNotFound;
44   }
45   NOTREACHED();
46   return blink::WebServiceWorkerCacheErrorNotImplemented;
47 }
48
49 // TODO(jkarlin): ServiceWorkerCache and ServiceWorkerCacheStorage should share
50 // an error enum type.
51 WebServiceWorkerCacheError CacheErrorToWebServiceWorkerCacheError(
52     ServiceWorkerCache::ErrorType err) {
53   switch (err) {
54     case ServiceWorkerCache::ErrorTypeOK:
55       NOTREACHED();
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
61       // added.
62       return blink::WebServiceWorkerCacheErrorNotFound;
63     case ServiceWorkerCache::ErrorTypeNotFound:
64       return blink::WebServiceWorkerCacheErrorNotFound;
65   }
66   NOTREACHED();
67   return blink::WebServiceWorkerCacheErrorNotImplemented;
68 }
69
70 }  // namespace
71
72 ServiceWorkerCacheListener::ServiceWorkerCacheListener(
73     ServiceWorkerVersion* version,
74     base::WeakPtr<ServiceWorkerContextCore> context)
75     : version_(version),
76       context_(context),
77       next_cache_id_(0),
78       weak_factory_(this) {
79   version_->embedded_worker()->AddListener(this);
80 }
81
82 ServiceWorkerCacheListener::~ServiceWorkerCacheListener() {
83   version_->embedded_worker()->RemoveListener(this);
84 }
85
86 bool ServiceWorkerCacheListener::OnMessageReceived(
87     const IPC::Message& message) {
88   bool handled = true;
89   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerCacheListener, message)
90     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageHas,
91                         OnCacheStorageHas)
92     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageOpen,
93                         OnCacheStorageOpen)
94     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageDelete,
95                         OnCacheStorageDelete)
96     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageKeys,
97                         OnCacheStorageKeys)
98     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheMatch,
99                         OnCacheMatch)
100     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheMatchAll,
101                         OnCacheMatchAll)
102     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheKeys,
103                         OnCacheKeys)
104     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheBatch,
105                         OnCacheBatch)
106     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheClosed,
107                         OnCacheClosed)
108     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_BlobDataHandled, OnBlobDataHandled)
109     IPC_MESSAGE_UNHANDLED(handled = false)
110   IPC_END_MESSAGE_MAP()
111
112   return handled;
113 }
114
115 void ServiceWorkerCacheListener::OnCacheStorageHas(
116     int request_id,
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(),
125                  request_id));
126 }
127
128 void ServiceWorkerCacheListener::OnCacheStorageOpen(
129     int request_id,
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(),
138                  request_id));
139 }
140
141 void ServiceWorkerCacheListener::OnCacheStorageDelete(
142     int request_id,
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(),
151                  request_id));
152 }
153
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(),
161                  request_id));
162 }
163
164 void ServiceWorkerCacheListener::OnCacheMatch(
165     int request_id,
166     int cache_id,
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));
173     return;
174   }
175
176   scoped_refptr<ServiceWorkerCache> cache = it->second;
177   scoped_ptr<ServiceWorkerFetchRequest> scoped_request(
178       new ServiceWorkerFetchRequest(request.url,
179                                     request.method,
180                                     request.headers,
181                                     request.referrer,
182                                     request.is_reload));
183   cache->Match(scoped_request.Pass(),
184                base::Bind(&ServiceWorkerCacheListener::OnCacheMatchCallback,
185                           weak_factory_.GetWeakPtr(),
186                           request_id,
187                           cache));
188 }
189
190 void ServiceWorkerCacheListener::OnCacheMatchAll(
191     int request_id,
192     int cache_id,
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));
198 }
199
200 void ServiceWorkerCacheListener::OnCacheKeys(
201     int request_id,
202     int cache_id,
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));
209     return;
210   }
211
212   scoped_refptr<ServiceWorkerCache> cache = it->second;
213
214   cache->Keys(base::Bind(&ServiceWorkerCacheListener::OnCacheKeysCallback,
215                          weak_factory_.GetWeakPtr(),
216                          request_id,
217                          cache));
218 }
219
220 void ServiceWorkerCacheListener::OnCacheBatch(
221     int request_id,
222     int cache_id,
223     const std::vector<ServiceWorkerBatchOperation>& operations) {
224   if (operations.size() != 1u) {
225     Send(ServiceWorkerMsg_CacheBatchError(
226         request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
227     return;
228   }
229
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));
234     return;
235   }
236
237   const ServiceWorkerBatchOperation& operation = operations[0];
238
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));
246
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(),
251                              request_id,
252                              cache));
253     return;
254   }
255
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(),
269                           request_id,
270                           cache));
271
272     return;
273   }
274
275   Send(ServiceWorkerMsg_CacheBatchError(
276       request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
277 }
278
279 void ServiceWorkerCacheListener::OnCacheClosed(int cache_id) {
280   DropCacheReference(cache_id);
281 }
282
283 void ServiceWorkerCacheListener::OnBlobDataHandled(const std::string& uuid) {
284   DropBlobDataHandle(uuid);
285 }
286
287 void ServiceWorkerCacheListener::Send(const IPC::Message& message) {
288   version_->embedded_worker()->SendMessage(message);
289 }
290
291 void ServiceWorkerCacheListener::OnCacheStorageHasCallback(
292     int request_id,
293     bool has_cache,
294     ServiceWorkerCacheStorage::CacheStorageError error) {
295   if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
296     Send(ServiceWorkerMsg_CacheStorageHasError(
297         request_id, ToWebServiceWorkerCacheError(error)));
298     return;
299   }
300   if (!has_cache) {
301     Send(ServiceWorkerMsg_CacheStorageHasError(
302         request_id,
303         blink::WebServiceWorkerCacheErrorNotFound));
304     return;
305   }
306   Send(ServiceWorkerMsg_CacheStorageHasSuccess(request_id));
307 }
308
309 void ServiceWorkerCacheListener::OnCacheStorageOpenCallback(
310     int request_id,
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)));
316     return;
317   }
318   CacheID cache_id = StoreCacheReference(cache);
319   Send(ServiceWorkerMsg_CacheStorageOpenSuccess(request_id, cache_id));
320 }
321
322 void ServiceWorkerCacheListener::OnCacheStorageDeleteCallback(
323     int request_id,
324     bool deleted,
325     ServiceWorkerCacheStorage::CacheStorageError error) {
326   if (!deleted ||
327       error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
328     Send(ServiceWorkerMsg_CacheStorageDeleteError(
329         request_id, ToWebServiceWorkerCacheError(error)));
330     return;
331   }
332   Send(ServiceWorkerMsg_CacheStorageDeleteSuccess(request_id));
333 }
334
335 void ServiceWorkerCacheListener::OnCacheStorageKeysCallback(
336     int request_id,
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)));
342     return;
343   }
344
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]));
348   }
349   Send(ServiceWorkerMsg_CacheStorageKeysSuccess(request_id, string16s));
350 }
351
352 void ServiceWorkerCacheListener::OnCacheMatchCallback(
353     int request_id,
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)));
361     return;
362   }
363
364   if (blob_data_handle)
365     StoreBlobDataHandle(blob_data_handle.Pass());
366
367   Send(ServiceWorkerMsg_CacheMatchSuccess(request_id, *response));
368 }
369
370 void ServiceWorkerCacheListener::OnCacheKeysCallback(
371     int request_id,
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)));
378     return;
379   }
380
381   ServiceWorkerCache::Requests out;
382
383   for (ServiceWorkerCache::Requests::const_iterator it = requests->begin();
384        it != requests->end();
385        ++it) {
386     ServiceWorkerFetchRequest request(
387         it->url, it->method, it->headers, it->referrer, it->is_reload);
388     out.push_back(request);
389   }
390
391   Send(ServiceWorkerMsg_CacheKeysSuccess(request_id, out));
392 }
393
394 void ServiceWorkerCacheListener::OnCacheDeleteCallback(
395     int request_id,
396     const scoped_refptr<ServiceWorkerCache>& cache,
397     ServiceWorkerCache::ErrorType error) {
398   if (error != ServiceWorkerCache::ErrorTypeOK) {
399     Send(ServiceWorkerMsg_CacheBatchError(
400         request_id, CacheErrorToWebServiceWorkerCacheError(error)));
401     return;
402   }
403
404   Send(ServiceWorkerMsg_CacheBatchSuccess(
405       request_id, std::vector<ServiceWorkerResponse>()));
406 }
407
408 void ServiceWorkerCacheListener::OnCachePutCallback(
409     int request_id,
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)));
417     return;
418   }
419
420   if (blob_data_handle)
421     StoreBlobDataHandle(blob_data_handle.Pass());
422
423   std::vector<ServiceWorkerResponse> responses;
424   responses.push_back(*response);
425   Send(ServiceWorkerMsg_CacheBatchSuccess(request_id, responses));
426 }
427
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;
433   return cache_id;
434 }
435
436 void ServiceWorkerCacheListener::DropCacheReference(CacheID cache_id) {
437   id_to_cache_map_.erase(cache_id);
438 }
439
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));
447 }
448
449 void ServiceWorkerCacheListener::DropBlobDataHandle(std::string uuid) {
450   UUIDToBlobDataHandleList::iterator it = blob_handle_store_.find(uuid);
451   if (it == blob_handle_store_.end())
452     return;
453   DCHECK(!it->second.empty());
454   it->second.pop_front();
455   if (it->second.empty())
456     blob_handle_store_.erase(it);
457 }
458
459 }  // namespace content