| OLD | NEW |
| (Empty) |
| 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/ExceptionState.h" | |
| 9 #include "bindings/core/v8/ScriptPromiseResolver.h" | |
| 10 #include "bindings/core/v8/ScriptState.h" | |
| 11 #include "bindings/core/v8/V8ThrowException.h" | |
| 12 #include "core/dom/DOMException.h" | |
| 13 #include "modules/fetch/BodyStreamBuffer.h" | |
| 14 #include "modules/fetch/Request.h" | |
| 15 #include "modules/fetch/Response.h" | |
| 16 #include "public/platform/WebServiceWorkerCache.h" | |
| 17 | |
| 18 namespace blink { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // FIXME: Consider using CallbackPromiseAdapter. | |
| 23 class CacheMatchCallbacks : public WebServiceWorkerCache::CacheMatchCallbacks { | |
| 24 WTF_MAKE_NONCOPYABLE(CacheMatchCallbacks); | |
| 25 public: | |
| 26 CacheMatchCallbacks(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) | |
| 27 : m_resolver(resolver) { } | |
| 28 | |
| 29 virtual void onSuccess(WebServiceWorkerResponse* webResponse) override | |
| 30 { | |
| 31 m_resolver->resolve(Response::create(m_resolver->scriptState()->executio
nContext(), *webResponse)); | |
| 32 m_resolver.clear(); | |
| 33 } | |
| 34 | |
| 35 virtual void onError(WebServiceWorkerCacheError* reason) override | |
| 36 { | |
| 37 if (*reason == WebServiceWorkerCacheErrorNotFound) | |
| 38 m_resolver->resolve(); | |
| 39 else | |
| 40 m_resolver->reject(Cache::domExceptionForCacheError(*reason)); | |
| 41 m_resolver.clear(); | |
| 42 } | |
| 43 | |
| 44 private: | |
| 45 RefPtrWillBePersistent<ScriptPromiseResolver> m_resolver; | |
| 46 }; | |
| 47 | |
| 48 // FIXME: Consider using CallbackPromiseAdapter. | |
| 49 class CacheWithResponsesCallbacks : public WebServiceWorkerCache::CacheWithRespo
nsesCallbacks { | |
| 50 WTF_MAKE_NONCOPYABLE(CacheWithResponsesCallbacks); | |
| 51 public: | |
| 52 CacheWithResponsesCallbacks(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> re
solver) | |
| 53 : m_resolver(resolver) { } | |
| 54 | |
| 55 virtual void onSuccess(WebVector<WebServiceWorkerResponse>* webResponses) ov
erride | |
| 56 { | |
| 57 HeapVector<Member<Response>> responses; | |
| 58 for (size_t i = 0; i < webResponses->size(); ++i) | |
| 59 responses.append(Response::create(m_resolver->scriptState()->executi
onContext(), (*webResponses)[i])); | |
| 60 m_resolver->resolve(responses); | |
| 61 m_resolver.clear(); | |
| 62 } | |
| 63 | |
| 64 virtual void onError(WebServiceWorkerCacheError* reason) override | |
| 65 { | |
| 66 m_resolver->reject(Cache::domExceptionForCacheError(*reason)); | |
| 67 m_resolver.clear(); | |
| 68 } | |
| 69 | |
| 70 protected: | |
| 71 RefPtrWillBePersistent<ScriptPromiseResolver> m_resolver; | |
| 72 }; | |
| 73 | |
| 74 // FIXME: Consider using CallbackPromiseAdapter. | |
| 75 class CacheAddOrPutCallbacks : public CacheWithResponsesCallbacks { | |
| 76 WTF_MAKE_NONCOPYABLE(CacheAddOrPutCallbacks); | |
| 77 public: | |
| 78 CacheAddOrPutCallbacks(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolve
r) | |
| 79 : CacheWithResponsesCallbacks(resolver) { } | |
| 80 | |
| 81 virtual void onSuccess(WebVector<WebServiceWorkerResponse>* webResponses) ov
erride | |
| 82 { | |
| 83 // FIXME: Since response is ignored, consider simplifying public API. | |
| 84 m_resolver->resolve(); | |
| 85 m_resolver.clear(); | |
| 86 } | |
| 87 }; | |
| 88 | |
| 89 // FIXME: Consider using CallbackPromiseAdapter. | |
| 90 class CacheDeleteCallback : public WebServiceWorkerCache::CacheWithResponsesCall
backs { | |
| 91 WTF_MAKE_NONCOPYABLE(CacheDeleteCallback); | |
| 92 public: | |
| 93 CacheDeleteCallback(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver) | |
| 94 : m_resolver(resolver) { } | |
| 95 | |
| 96 virtual void onSuccess(WebVector<WebServiceWorkerResponse>* webResponses) ov
erride | |
| 97 { | |
| 98 // FIXME: Since response is ignored, consider simplifying public API. | |
| 99 m_resolver->resolve(true); | |
| 100 m_resolver.clear(); | |
| 101 } | |
| 102 | |
| 103 virtual void onError(WebServiceWorkerCacheError* reason) override | |
| 104 { | |
| 105 if (*reason == WebServiceWorkerCacheErrorNotFound) | |
| 106 m_resolver->resolve(false); | |
| 107 else | |
| 108 m_resolver->reject(Cache::domExceptionForCacheError(*reason)); | |
| 109 m_resolver.clear(); | |
| 110 } | |
| 111 | |
| 112 private: | |
| 113 RefPtrWillBePersistent<ScriptPromiseResolver> m_resolver; | |
| 114 }; | |
| 115 | |
| 116 // FIXME: Consider using CallbackPromiseAdapter. | |
| 117 class CacheWithRequestsCallbacks : public WebServiceWorkerCache::CacheWithReques
tsCallbacks { | |
| 118 WTF_MAKE_NONCOPYABLE(CacheWithRequestsCallbacks); | |
| 119 public: | |
| 120 CacheWithRequestsCallbacks(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> res
olver) | |
| 121 : m_resolver(resolver) { } | |
| 122 | |
| 123 virtual void onSuccess(WebVector<WebServiceWorkerRequest>* webRequests) over
ride | |
| 124 { | |
| 125 HeapVector<Member<Request>> requests; | |
| 126 for (size_t i = 0; i < webRequests->size(); ++i) | |
| 127 requests.append(Request::create(m_resolver->scriptState()->execution
Context(), (*webRequests)[i])); | |
| 128 m_resolver->resolve(requests); | |
| 129 m_resolver.clear(); | |
| 130 } | |
| 131 | |
| 132 virtual void onError(WebServiceWorkerCacheError* reason) override | |
| 133 { | |
| 134 m_resolver->reject(Cache::domExceptionForCacheError(*reason)); | |
| 135 m_resolver.clear(); | |
| 136 } | |
| 137 | |
| 138 private: | |
| 139 RefPtrWillBePersistent<ScriptPromiseResolver> m_resolver; | |
| 140 }; | |
| 141 | |
| 142 ScriptPromise rejectAsNotImplemented(ScriptState* scriptState) | |
| 143 { | |
| 144 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::crea
te(NotSupportedError, "Cache is not implemented")); | |
| 145 } | |
| 146 | |
| 147 } // namespace | |
| 148 | |
| 149 class Cache::AsyncPutBatch final : public BodyStreamBuffer::BlobHandleCreatorCli
ent { | |
| 150 public: | |
| 151 AsyncPutBatch(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver, Cache*
cache, Request* request, Response* response) | |
| 152 : m_resolver(resolver) | |
| 153 , m_cache(cache) | |
| 154 { | |
| 155 request->populateWebServiceWorkerRequest(m_webRequest); | |
| 156 response->populateWebServiceWorkerResponse(m_webResponse); | |
| 157 } | |
| 158 ~AsyncPutBatch() override { } | |
| 159 void didCreateBlobHandle(PassRefPtr<BlobDataHandle> handle) override | |
| 160 { | |
| 161 WebVector<WebServiceWorkerCache::BatchOperation> batchOperations(size_t(
1)); | |
| 162 batchOperations[0].operationType = WebServiceWorkerCache::OperationTypeP
ut; | |
| 163 batchOperations[0].request = m_webRequest; | |
| 164 batchOperations[0].response = m_webResponse; | |
| 165 batchOperations[0].response.setBlobDataHandle(handle); | |
| 166 m_cache->webCache()->dispatchBatch(new CacheAddOrPutCallbacks(m_resolver
.get()), batchOperations); | |
| 167 cleanup(); | |
| 168 } | |
| 169 void didFail(PassRefPtrWillBeRawPtr<DOMException> exception) override | |
| 170 { | |
| 171 ScriptState* state = m_resolver->scriptState(); | |
| 172 ScriptState::Scope scope(state); | |
| 173 m_resolver->reject(V8ThrowException::createTypeError(state->isolate(), e
xception->toString())); | |
| 174 cleanup(); | |
| 175 } | |
| 176 | |
| 177 DEFINE_INLINE_VIRTUAL_TRACE() | |
| 178 { | |
| 179 visitor->trace(m_resolver); | |
| 180 visitor->trace(m_cache); | |
| 181 BlobHandleCreatorClient::trace(visitor); | |
| 182 } | |
| 183 | |
| 184 private: | |
| 185 void cleanup() | |
| 186 { | |
| 187 m_resolver = nullptr; | |
| 188 m_cache = nullptr; | |
| 189 } | |
| 190 RefPtrWillBeMember<ScriptPromiseResolver> m_resolver; | |
| 191 Member<Cache> m_cache; | |
| 192 WebServiceWorkerRequest m_webRequest; | |
| 193 WebServiceWorkerResponse m_webResponse; | |
| 194 }; | |
| 195 | |
| 196 Cache* Cache::create(WebServiceWorkerCache* webCache) | |
| 197 { | |
| 198 return new Cache(webCache); | |
| 199 } | |
| 200 | |
| 201 ScriptPromise Cache::match(ScriptState* scriptState, const RequestInfo& request,
const CacheQueryOptions& options, ExceptionState& exceptionState) | |
| 202 { | |
| 203 ASSERT(!request.isNull()); | |
| 204 if (request.isRequest()) | |
| 205 return matchImpl(scriptState, request.getAsRequest(), options); | |
| 206 Request* newRequest = Request::create(scriptState->executionContext(), reque
st.getAsUSVString(), exceptionState); | |
| 207 if (exceptionState.hadException()) | |
| 208 return ScriptPromise(); | |
| 209 return matchImpl(scriptState, newRequest, options); | |
| 210 } | |
| 211 | |
| 212 ScriptPromise Cache::matchAll(ScriptState* scriptState, const RequestInfo& reque
st, const CacheQueryOptions& options, ExceptionState& exceptionState) | |
| 213 { | |
| 214 ASSERT(!request.isNull()); | |
| 215 if (request.isRequest()) | |
| 216 return matchAllImpl(scriptState, request.getAsRequest(), options); | |
| 217 Request* newRequest = Request::create(scriptState->executionContext(), reque
st.getAsUSVString(), exceptionState); | |
| 218 if (exceptionState.hadException()) | |
| 219 return ScriptPromise(); | |
| 220 return matchAllImpl(scriptState, newRequest, options); | |
| 221 } | |
| 222 | |
| 223 ScriptPromise Cache::add(ScriptState* scriptState, const RequestInfo& request, E
xceptionState& exceptionState) | |
| 224 { | |
| 225 ASSERT(!request.isNull()); | |
| 226 if (request.isRequest()) | |
| 227 return addImpl(scriptState, request.getAsRequest()); | |
| 228 Request* newRequest = Request::create(scriptState->executionContext(), reque
st.getAsUSVString(), exceptionState); | |
| 229 if (exceptionState.hadException()) | |
| 230 return ScriptPromise(); | |
| 231 return addImpl(scriptState, newRequest); | |
| 232 } | |
| 233 | |
| 234 ScriptPromise Cache::addAll(ScriptState* scriptState, const Vector<ScriptValue>&
rawRequests) | |
| 235 { | |
| 236 // FIXME: Implement this. | |
| 237 return rejectAsNotImplemented(scriptState); | |
| 238 } | |
| 239 | |
| 240 ScriptPromise Cache::deleteFunction(ScriptState* scriptState, const RequestInfo&
request, const CacheQueryOptions& options, ExceptionState& exceptionState) | |
| 241 { | |
| 242 ASSERT(!request.isNull()); | |
| 243 if (request.isRequest()) | |
| 244 return deleteImpl(scriptState, request.getAsRequest(), options); | |
| 245 Request* newRequest = Request::create(scriptState->executionContext(), reque
st.getAsUSVString(), exceptionState); | |
| 246 if (exceptionState.hadException()) | |
| 247 return ScriptPromise(); | |
| 248 return deleteImpl(scriptState, newRequest, options); | |
| 249 } | |
| 250 | |
| 251 ScriptPromise Cache::put(ScriptState* scriptState, const RequestInfo& request, R
esponse* response, ExceptionState& exceptionState) | |
| 252 { | |
| 253 ASSERT(!request.isNull()); | |
| 254 if (request.isRequest()) | |
| 255 return putImpl(scriptState, request.getAsRequest(), response); | |
| 256 Request* newRequest = Request::create(scriptState->executionContext(), reque
st.getAsUSVString(), exceptionState); | |
| 257 if (exceptionState.hadException()) | |
| 258 return ScriptPromise(); | |
| 259 return putImpl(scriptState, newRequest, response); | |
| 260 } | |
| 261 | |
| 262 ScriptPromise Cache::keys(ScriptState* scriptState, ExceptionState&) | |
| 263 { | |
| 264 return keysImpl(scriptState); | |
| 265 } | |
| 266 | |
| 267 ScriptPromise Cache::keys(ScriptState* scriptState, const RequestInfo& request,
const CacheQueryOptions& options, ExceptionState& exceptionState) | |
| 268 { | |
| 269 ASSERT(!request.isNull()); | |
| 270 if (request.isRequest()) | |
| 271 return keysImpl(scriptState, request.getAsRequest(), options); | |
| 272 Request* newRequest = Request::create(scriptState->executionContext(), reque
st.getAsUSVString(), exceptionState); | |
| 273 if (exceptionState.hadException()) | |
| 274 return ScriptPromise(); | |
| 275 return keysImpl(scriptState, newRequest, options); | |
| 276 } | |
| 277 | |
| 278 // static | |
| 279 WebServiceWorkerCache::QueryParams Cache::toWebQueryParams(const CacheQueryOptio
ns& options) | |
| 280 { | |
| 281 WebServiceWorkerCache::QueryParams webQueryParams; | |
| 282 webQueryParams.ignoreSearch = options.ignoreSearch(); | |
| 283 webQueryParams.ignoreMethod = options.ignoreMethod(); | |
| 284 webQueryParams.ignoreVary = options.ignoreVary(); | |
| 285 webQueryParams.cacheName = options.cacheName(); | |
| 286 return webQueryParams; | |
| 287 } | |
| 288 | |
| 289 Cache::Cache(WebServiceWorkerCache* webCache) | |
| 290 : m_webCache(adoptPtr(webCache)) { } | |
| 291 | |
| 292 ScriptPromise Cache::matchImpl(ScriptState* scriptState, const Request* request,
const CacheQueryOptions& options) | |
| 293 { | |
| 294 WebServiceWorkerRequest webRequest; | |
| 295 request->populateWebServiceWorkerRequest(webRequest); | |
| 296 | |
| 297 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | |
| 298 const ScriptPromise promise = resolver->promise(); | |
| 299 m_webCache->dispatchMatch(new CacheMatchCallbacks(resolver), webRequest, toW
ebQueryParams(options)); | |
| 300 return promise; | |
| 301 } | |
| 302 | |
| 303 ScriptPromise Cache::matchAllImpl(ScriptState* scriptState, const Request* reque
st, const CacheQueryOptions& options) | |
| 304 { | |
| 305 WebServiceWorkerRequest webRequest; | |
| 306 request->populateWebServiceWorkerRequest(webRequest); | |
| 307 | |
| 308 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | |
| 309 const ScriptPromise promise = resolver->promise(); | |
| 310 m_webCache->dispatchMatchAll(new CacheWithResponsesCallbacks(resolver), webR
equest, toWebQueryParams(options)); | |
| 311 return promise; | |
| 312 } | |
| 313 | |
| 314 ScriptPromise Cache::addImpl(ScriptState* scriptState, const Request*) | |
| 315 { | |
| 316 // FIXME: Implement this. | |
| 317 return rejectAsNotImplemented(scriptState); | |
| 318 } | |
| 319 | |
| 320 ScriptPromise Cache::addAllImpl(ScriptState* scriptState, const Vector<const Req
uest*>) | |
| 321 { | |
| 322 // FIXME: Implement this. | |
| 323 return rejectAsNotImplemented(scriptState); | |
| 324 } | |
| 325 | |
| 326 PassRefPtrWillBeRawPtr<DOMException> Cache::domExceptionForCacheError(WebService
WorkerCacheError reason) | |
| 327 { | |
| 328 switch (reason) { | |
| 329 case WebServiceWorkerCacheErrorNotImplemented: | |
| 330 return DOMException::create(NotSupportedError, "Method is not implemente
d."); | |
| 331 case WebServiceWorkerCacheErrorNotFound: | |
| 332 return DOMException::create(NotFoundError, "Entry was not found."); | |
| 333 case WebServiceWorkerCacheErrorExists: | |
| 334 return DOMException::create(InvalidAccessError, "Entry already exists.")
; | |
| 335 default: | |
| 336 ASSERT_NOT_REACHED(); | |
| 337 return DOMException::create(NotSupportedError, "Unknown error."); | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 ScriptPromise Cache::deleteImpl(ScriptState* scriptState, const Request* request
, const CacheQueryOptions& options) | |
| 342 { | |
| 343 WebVector<WebServiceWorkerCache::BatchOperation> batchOperations(size_t(1)); | |
| 344 batchOperations[0].operationType = WebServiceWorkerCache::OperationTypeDelet
e; | |
| 345 request->populateWebServiceWorkerRequest(batchOperations[0].request); | |
| 346 batchOperations[0].matchParams = toWebQueryParams(options); | |
| 347 | |
| 348 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | |
| 349 const ScriptPromise promise = resolver->promise(); | |
| 350 m_webCache->dispatchBatch(new CacheDeleteCallback(resolver), batchOperations
); | |
| 351 return promise; | |
| 352 } | |
| 353 | |
| 354 ScriptPromise Cache::putImpl(ScriptState* scriptState, Request* request, Respons
e* response) | |
| 355 { | |
| 356 KURL url(KURL(), request->url()); | |
| 357 if (!url.protocolIsInHTTPFamily()) | |
| 358 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr
ror(scriptState->isolate(), "Request scheme '" + url.protocol() + "' is unsuppor
ted")); | |
| 359 if (request->method() != "GET") | |
| 360 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr
ror(scriptState->isolate(), "Request method '" + request->method() + "' is unsup
ported")); | |
| 361 if (request->hasBody() && request->bodyUsed()) | |
| 362 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr
ror(scriptState->isolate(), "Request body is already used")); | |
| 363 if (response->hasBody() && response->bodyUsed()) | |
| 364 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr
ror(scriptState->isolate(), "Response body is already used")); | |
| 365 | |
| 366 if (request->hasBody()) | |
| 367 request->lockBody(Body::PassBody); | |
| 368 if (response->hasBody()) | |
| 369 response->lockBody(Body::PassBody); | |
| 370 | |
| 371 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | |
| 372 const ScriptPromise promise = resolver->promise(); | |
| 373 if (BodyStreamBuffer* buffer = response->internalBuffer()) { | |
| 374 if (buffer == response->buffer() && response->isBodyConsumed()) | |
| 375 buffer = response->createDrainingStream(); | |
| 376 // If the response body type is stream, read the all data and create the | |
| 377 // blob handle and dispatch the put batch asynchronously. | |
| 378 buffer->readAllAndCreateBlobHandle(response->internalMIMEType(), new Asy
ncPutBatch(resolver, this, request, response)); | |
| 379 return promise; | |
| 380 } | |
| 381 WebVector<WebServiceWorkerCache::BatchOperation> batchOperations(size_t(1)); | |
| 382 batchOperations[0].operationType = WebServiceWorkerCache::OperationTypePut; | |
| 383 request->populateWebServiceWorkerRequest(batchOperations[0].request); | |
| 384 response->populateWebServiceWorkerResponse(batchOperations[0].response); | |
| 385 | |
| 386 m_webCache->dispatchBatch(new CacheAddOrPutCallbacks(resolver), batchOperati
ons); | |
| 387 return promise; | |
| 388 } | |
| 389 | |
| 390 ScriptPromise Cache::keysImpl(ScriptState* scriptState) | |
| 391 { | |
| 392 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | |
| 393 const ScriptPromise promise = resolver->promise(); | |
| 394 m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), 0, WebSer
viceWorkerCache::QueryParams()); | |
| 395 return promise; | |
| 396 } | |
| 397 | |
| 398 ScriptPromise Cache::keysImpl(ScriptState* scriptState, const Request* request,
const CacheQueryOptions& options) | |
| 399 { | |
| 400 WebServiceWorkerRequest webRequest; | |
| 401 request->populateWebServiceWorkerRequest(webRequest); | |
| 402 | |
| 403 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | |
| 404 const ScriptPromise promise = resolver->promise(); | |
| 405 m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), 0, toWebQ
ueryParams(options)); | |
| 406 return promise; | |
| 407 } | |
| 408 | |
| 409 WebServiceWorkerCache* Cache::webCache() const | |
| 410 { | |
| 411 return m_webCache.get(); | |
| 412 } | |
| 413 | |
| 414 } // namespace blink | |
| OLD | NEW |