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