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 |