Home | History | Annotate | Download | only in serviceworkers
      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 "config.h"
      6 #include "modules/serviceworkers/Cache.h"
      7 
      8 #include "bindings/core/v8/ScriptPromiseResolver.h"
      9 #include "bindings/core/v8/ScriptState.h"
     10 #include "bindings/core/v8/V8ThrowException.h"
     11 #include "core/dom/DOMException.h"
     12 #include "modules/serviceworkers/Request.h"
     13 #include "modules/serviceworkers/Response.h"
     14 #include "public/platform/WebServiceWorkerCache.h"
     15 
     16 namespace blink {
     17 
     18 namespace {
     19 
     20 WebServiceWorkerCache::QueryParams toWebQueryParams(const QueryParams& queryParams)
     21 {
     22     WebServiceWorkerCache::QueryParams webQueryParams;
     23     // FIXME: The queryParams.hasXXXX() calls can be removed if defaults are
     24     // added to the IDL. https://github.com/slightlyoff/ServiceWorker/issues/466
     25     webQueryParams.ignoreSearch = queryParams.hasIgnoreSearch() && queryParams.ignoreSearch();
     26     webQueryParams.ignoreMethod = queryParams.hasIgnoreMethod() && queryParams.ignoreMethod();
     27     webQueryParams.ignoreVary = queryParams.hasIgnoreVary() && queryParams.ignoreVary();
     28     webQueryParams.prefixMatch = queryParams.hasPrefixMatch() && queryParams.prefixMatch();
     29     webQueryParams.cacheName = queryParams.cacheName();
     30     return webQueryParams;
     31 }
     32 
     33 // FIXME: Consider using CallbackPromiseAdapter.
     34 class CacheMatchCallbacks : public WebServiceWorkerCache::CacheMatchCallbacks {
     35     WTF_MAKE_NONCOPYABLE(CacheMatchCallbacks);
     36 public:
     37     CacheMatchCallbacks(PassRefPtr<ScriptPromiseResolver> resolver)
     38         : m_resolver(resolver) { }
     39 
     40     virtual void onSuccess(WebServiceWorkerResponse* webResponse) OVERRIDE
     41     {
     42         m_resolver->resolve(Response::create(m_resolver->scriptState()->executionContext(), *webResponse));
     43         m_resolver.clear();
     44     }
     45 
     46     virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
     47     {
     48         m_resolver->reject(Cache::domExceptionForCacheError(*reason));
     49         m_resolver.clear();
     50     }
     51 
     52 private:
     53     RefPtr<ScriptPromiseResolver> m_resolver;
     54 };
     55 
     56 // FIXME: Consider using CallbackPromiseAdapter.
     57 class CacheWithResponsesCallbacks : public WebServiceWorkerCache::CacheWithResponsesCallbacks {
     58     WTF_MAKE_NONCOPYABLE(CacheWithResponsesCallbacks);
     59 public:
     60     CacheWithResponsesCallbacks(PassRefPtr<ScriptPromiseResolver> resolver)
     61         : m_resolver(resolver) { }
     62 
     63     virtual void onSuccess(WebVector<WebServiceWorkerResponse>* webResponses) OVERRIDE
     64     {
     65         HeapVector<Member<Response> > responses;
     66         for (size_t i = 0; i < webResponses->size(); ++i)
     67             responses.append(Response::create(m_resolver->scriptState()->executionContext(), (*webResponses)[i]));
     68         m_resolver->resolve(responses);
     69         m_resolver.clear();
     70     }
     71 
     72     virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
     73     {
     74         m_resolver->reject(Cache::domExceptionForCacheError(*reason));
     75         m_resolver.clear();
     76     }
     77 
     78 private:
     79     RefPtr<ScriptPromiseResolver> m_resolver;
     80 };
     81 
     82 // FIXME: Consider using CallbackPromiseAdapter.
     83 class CacheWithRequestsCallbacks : public WebServiceWorkerCache::CacheWithRequestsCallbacks {
     84     WTF_MAKE_NONCOPYABLE(CacheWithRequestsCallbacks);
     85 public:
     86     CacheWithRequestsCallbacks(PassRefPtr<ScriptPromiseResolver> resolver)
     87         : m_resolver(resolver) { }
     88 
     89     virtual void onSuccess(WebVector<WebServiceWorkerRequest>* webRequests) OVERRIDE
     90     {
     91         HeapVector<Member<Request> > requests;
     92         for (size_t i = 0; i < webRequests->size(); ++i)
     93             requests.append(Request::create(m_resolver->scriptState()->executionContext(), (*webRequests)[i]));
     94         m_resolver->resolve(requests);
     95         m_resolver.clear();
     96     }
     97 
     98     virtual void onError(WebServiceWorkerCacheError* reason) OVERRIDE
     99     {
    100         m_resolver->reject(Cache::domExceptionForCacheError(*reason));
    101         m_resolver.clear();
    102     }
    103 
    104 private:
    105     RefPtr<ScriptPromiseResolver> m_resolver;
    106 };
    107 
    108 ScriptPromise rejectForCacheError(ScriptState* scriptState, WebServiceWorkerCacheError error)
    109 {
    110     return ScriptPromise::rejectWithDOMException(scriptState, Cache::domExceptionForCacheError(error));
    111 }
    112 
    113 ScriptPromise rejectAsNotImplemented(ScriptState* scriptState)
    114 {
    115     return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError, "Cache is not implemented"));
    116 }
    117 
    118 } // namespace
    119 
    120 Cache* Cache::create(WebServiceWorkerCache* webCache)
    121 {
    122     return new Cache(webCache);
    123 }
    124 
    125 ScriptPromise Cache::match(ScriptState* scriptState, Request* originalRequest, const QueryParams& queryParams)
    126 {
    127     TrackExceptionState exceptionState;
    128     Request* request = Request::create(scriptState->executionContext(), originalRequest, exceptionState);
    129     if (exceptionState.hadException()) {
    130         // FIXME: We should throw the caught error.
    131         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    132     }
    133     return matchImpl(scriptState, request, queryParams);
    134 }
    135 
    136 ScriptPromise Cache::match(ScriptState* scriptState, const String& requestString, const QueryParams& queryParams)
    137 {
    138     TrackExceptionState exceptionState;
    139     Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState);
    140     if (exceptionState.hadException()) {
    141         // FIXME: We should throw the caught error.
    142         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    143     }
    144     return matchImpl(scriptState, request, queryParams);
    145 }
    146 
    147 ScriptPromise Cache::matchAll(ScriptState* scriptState, Request* originalRequest, const QueryParams& queryParams)
    148 {
    149     TrackExceptionState exceptionState;
    150     Request* request = Request::create(scriptState->executionContext(), originalRequest, exceptionState);
    151     if (exceptionState.hadException()) {
    152         // FIXME: We should throw the caught error.
    153         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    154     }
    155     return matchAllImpl(scriptState, request, queryParams);
    156 }
    157 
    158 ScriptPromise Cache::matchAll(ScriptState* scriptState, const String& requestString, const QueryParams& queryParams)
    159 {
    160     TrackExceptionState exceptionState;
    161     Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState);
    162     if (exceptionState.hadException()) {
    163         // FIXME: We should throw the caught error.
    164         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    165     }
    166     return matchAllImpl(scriptState, request, queryParams);
    167 }
    168 
    169 ScriptPromise Cache::add(ScriptState* scriptState, Request* originalRequest)
    170 {
    171     TrackExceptionState exceptionState;
    172     Request* request = Request::create(scriptState->executionContext(), originalRequest, exceptionState);
    173     if (exceptionState.hadException()) {
    174         // FIXME: We should throw the caught error.
    175         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    176     }
    177     return addImpl(scriptState, request);
    178 }
    179 
    180 ScriptPromise Cache::add(ScriptState* scriptState, const String& requestString)
    181 {
    182     TrackExceptionState exceptionState;
    183     Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState);
    184     if (exceptionState.hadException()) {
    185         // FIXME: We should throw the caught error.
    186         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    187     }
    188     return addImpl(scriptState, request);
    189 }
    190 
    191 ScriptPromise Cache::addAll(ScriptState* scriptState, const Vector<ScriptValue>& rawRequests)
    192 {
    193     // FIXME: Implement this.
    194     return rejectAsNotImplemented(scriptState);
    195 }
    196 
    197 ScriptPromise Cache::deleteFunction(ScriptState* scriptState, Request* originalRequest, const QueryParams& queryParams)
    198 {
    199     TrackExceptionState exceptionState;
    200     Request* request = Request::create(scriptState->executionContext(), originalRequest, exceptionState);
    201     if (exceptionState.hadException()) {
    202         // FIXME: We should throw the caught error.
    203         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    204     }
    205     return deleteImpl(scriptState, request, queryParams);
    206 }
    207 
    208 ScriptPromise Cache::deleteFunction(ScriptState* scriptState, const String& requestString, const QueryParams& queryParams)
    209 {
    210     TrackExceptionState exceptionState;
    211     Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState);
    212     if (exceptionState.hadException()) {
    213         // FIXME: We should throw the caught error.
    214         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    215     }
    216     return deleteImpl(scriptState, request, queryParams);
    217 }
    218 
    219 ScriptPromise Cache::put(ScriptState* scriptState, Request* originalRequest, Response* response)
    220 {
    221     TrackExceptionState exceptionState;
    222     Request* request = Request::create(scriptState->executionContext(), originalRequest, exceptionState);
    223     if (exceptionState.hadException()) {
    224         // FIXME: We should throw the caught error.
    225         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    226     }
    227     return putImpl(scriptState, request, response);
    228 }
    229 
    230 ScriptPromise Cache::put(ScriptState* scriptState, const String& requestString, Response* response)
    231 {
    232     TrackExceptionState exceptionState;
    233     Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState);
    234     if (exceptionState.hadException()) {
    235         // FIXME: We should throw the caught error.
    236         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    237     }
    238     return putImpl(scriptState, request, response);
    239 }
    240 
    241 ScriptPromise Cache::keys(ScriptState* scriptState)
    242 {
    243     return keysImpl(scriptState);
    244 }
    245 
    246 ScriptPromise Cache::keys(ScriptState* scriptState, Request* originalRequest, const QueryParams& queryParams)
    247 {
    248     TrackExceptionState exceptionState;
    249     Request* request = Request::create(scriptState->executionContext(), originalRequest, exceptionState);
    250     if (exceptionState.hadException()) {
    251         // FIXME: We should throw the caught error.
    252         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    253     }
    254     return keysImpl(scriptState, request, queryParams);
    255 }
    256 
    257 ScriptPromise Cache::keys(ScriptState* scriptState, const String& requestString, const QueryParams& queryParams)
    258 {
    259     TrackExceptionState exceptionState;
    260     Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState);
    261     if (exceptionState.hadException()) {
    262         // FIXME: We should throw the caught error.
    263         return rejectForCacheError(scriptState, WebServiceWorkerCacheErrorNotFound);
    264     }
    265     return keysImpl(scriptState, request, queryParams);
    266 }
    267 
    268 Cache::Cache(WebServiceWorkerCache* webCache)
    269     : m_webCache(adoptPtr(webCache)) { }
    270 
    271 ScriptPromise Cache::matchImpl(ScriptState* scriptState, Request* request, const QueryParams& queryParams)
    272 {
    273     WebServiceWorkerRequest webRequest;
    274     request->populateWebServiceWorkerRequest(webRequest);
    275 
    276     RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    277     const ScriptPromise promise = resolver->promise();
    278     m_webCache->dispatchMatch(new CacheMatchCallbacks(resolver), webRequest, toWebQueryParams(queryParams));
    279     return promise;
    280 }
    281 
    282 ScriptPromise Cache::matchAllImpl(ScriptState* scriptState, Request* request, const QueryParams& queryParams)
    283 {
    284     WebServiceWorkerRequest webRequest;
    285     request->populateWebServiceWorkerRequest(webRequest);
    286 
    287     RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    288     const ScriptPromise promise = resolver->promise();
    289     m_webCache->dispatchMatchAll(new CacheWithResponsesCallbacks(resolver), webRequest, toWebQueryParams(queryParams));
    290     return promise;
    291 }
    292 
    293 ScriptPromise Cache::addImpl(ScriptState* scriptState, Request*)
    294 {
    295     // FIXME: Implement this.
    296     return rejectAsNotImplemented(scriptState);
    297 }
    298 
    299 ScriptPromise Cache::addAllImpl(ScriptState* scriptState, Vector<Request*>)
    300 {
    301     // FIXME: Implement this.
    302     return rejectAsNotImplemented(scriptState);
    303 }
    304 
    305 PassRefPtrWillBeRawPtr<DOMException> Cache::domExceptionForCacheError(WebServiceWorkerCacheError reason)
    306 {
    307     switch (reason) {
    308     case WebServiceWorkerCacheErrorNotImplemented:
    309         return DOMException::create(NotSupportedError, "Method is not implemented.");
    310     case WebServiceWorkerCacheErrorNotFound:
    311         return DOMException::create(NotFoundError, "Entry was not found.");
    312     case WebServiceWorkerCacheErrorExists:
    313         return DOMException::create(InvalidAccessError, "Entry already exists.");
    314     default:
    315         ASSERT_NOT_REACHED();
    316         return DOMException::create(NotSupportedError, "Unknown error.");
    317     }
    318 }
    319 
    320 ScriptPromise Cache::deleteImpl(ScriptState* scriptState, Request* request, const QueryParams& queryParams)
    321 {
    322     WebVector<WebServiceWorkerCache::BatchOperation> batchOperations(size_t(1));
    323     batchOperations[0].operationType = WebServiceWorkerCache::OperationTypeDelete;
    324     request->populateWebServiceWorkerRequest(batchOperations[0].request);
    325     batchOperations[0].matchParams = toWebQueryParams(queryParams);
    326 
    327     RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    328     const ScriptPromise promise = resolver->promise();
    329     m_webCache->dispatchBatch(new CacheWithResponsesCallbacks(resolver), batchOperations);
    330     return promise;
    331 }
    332 
    333 ScriptPromise Cache::putImpl(ScriptState* scriptState, Request* request, Response* response)
    334 {
    335     WebVector<WebServiceWorkerCache::BatchOperation> batchOperations(size_t(1));
    336     batchOperations[0].operationType = WebServiceWorkerCache::OperationTypePut;
    337     request->populateWebServiceWorkerRequest(batchOperations[0].request);
    338     response->populateWebServiceWorkerResponse(batchOperations[0].response);
    339 
    340     RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    341     const ScriptPromise promise = resolver->promise();
    342     m_webCache->dispatchBatch(new CacheWithResponsesCallbacks(resolver), batchOperations);
    343     return promise;
    344 }
    345 
    346 ScriptPromise Cache::keysImpl(ScriptState* scriptState)
    347 {
    348     RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    349     const ScriptPromise promise = resolver->promise();
    350     m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), 0, WebServiceWorkerCache::QueryParams());
    351     return promise;
    352 }
    353 
    354 ScriptPromise Cache::keysImpl(ScriptState* scriptState, Request* request, const QueryParams& queryParams)
    355 {
    356     WebServiceWorkerRequest webRequest;
    357     request->populateWebServiceWorkerRequest(webRequest);
    358 
    359     RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    360     const ScriptPromise promise = resolver->promise();
    361     m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), 0, toWebQueryParams(queryParams));
    362     return promise;
    363 }
    364 
    365 } // namespace blink
    366