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 16namespace blink { 17 18namespace { 19 20WebServiceWorkerCache::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. 34class CacheMatchCallbacks : public WebServiceWorkerCache::CacheMatchCallbacks { 35 WTF_MAKE_NONCOPYABLE(CacheMatchCallbacks); 36public: 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 52private: 53 RefPtr<ScriptPromiseResolver> m_resolver; 54}; 55 56// FIXME: Consider using CallbackPromiseAdapter. 57class CacheWithResponsesCallbacks : public WebServiceWorkerCache::CacheWithResponsesCallbacks { 58 WTF_MAKE_NONCOPYABLE(CacheWithResponsesCallbacks); 59public: 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 78private: 79 RefPtr<ScriptPromiseResolver> m_resolver; 80}; 81 82// FIXME: Consider using CallbackPromiseAdapter. 83class CacheWithRequestsCallbacks : public WebServiceWorkerCache::CacheWithRequestsCallbacks { 84 WTF_MAKE_NONCOPYABLE(CacheWithRequestsCallbacks); 85public: 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 104private: 105 RefPtr<ScriptPromiseResolver> m_resolver; 106}; 107 108ScriptPromise rejectForCacheError(ScriptState* scriptState, WebServiceWorkerCacheError error) 109{ 110 return ScriptPromise::rejectWithDOMException(scriptState, Cache::domExceptionForCacheError(error)); 111} 112 113ScriptPromise rejectAsNotImplemented(ScriptState* scriptState) 114{ 115 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError, "Cache is not implemented")); 116} 117 118} // namespace 119 120Cache* Cache::create(WebServiceWorkerCache* webCache) 121{ 122 return new Cache(webCache); 123} 124 125ScriptPromise 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 136ScriptPromise 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 147ScriptPromise 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 158ScriptPromise 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 169ScriptPromise 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 180ScriptPromise 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 191ScriptPromise Cache::addAll(ScriptState* scriptState, const Vector<ScriptValue>& rawRequests) 192{ 193 // FIXME: Implement this. 194 return rejectAsNotImplemented(scriptState); 195} 196 197ScriptPromise 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 208ScriptPromise 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 219ScriptPromise 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 230ScriptPromise 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 241ScriptPromise Cache::keys(ScriptState* scriptState) 242{ 243 return keysImpl(scriptState); 244} 245 246ScriptPromise 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 257ScriptPromise 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 268Cache::Cache(WebServiceWorkerCache* webCache) 269 : m_webCache(adoptPtr(webCache)) { } 270 271ScriptPromise 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 282ScriptPromise 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 293ScriptPromise Cache::addImpl(ScriptState* scriptState, Request*) 294{ 295 // FIXME: Implement this. 296 return rejectAsNotImplemented(scriptState); 297} 298 299ScriptPromise Cache::addAllImpl(ScriptState* scriptState, Vector<Request*>) 300{ 301 // FIXME: Implement this. 302 return rejectAsNotImplemented(scriptState); 303} 304 305PassRefPtrWillBeRawPtr<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 320ScriptPromise 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 333ScriptPromise 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 346ScriptPromise 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 354ScriptPromise 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