1 | |
2 | /* |
3 | * Copyright (C) 2017 Apple Inc. All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
16 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
18 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
24 | * THE POSSIBILITY OF SUCH DAMAGE. |
25 | */ |
26 | |
27 | #include "config.h" |
28 | #include "WorkerCacheStorageConnection.h" |
29 | |
30 | #include "CacheQueryOptions.h" |
31 | #include "CacheStorageProvider.h" |
32 | #include "ClientOrigin.h" |
33 | #include "Document.h" |
34 | #include "Page.h" |
35 | #include "WorkerGlobalScope.h" |
36 | #include "WorkerLoaderProxy.h" |
37 | #include "WorkerRunLoop.h" |
38 | #include "WorkerThread.h" |
39 | |
40 | namespace WebCore { |
41 | using namespace WebCore::DOMCacheEngine; |
42 | |
43 | struct CrossThreadRecordData { |
44 | uint64_t identifier; |
45 | uint64_t updateResponseCounter; |
46 | |
47 | FetchHeaders::Guard ; |
48 | ResourceRequest request; |
49 | |
50 | FetchOptions options; |
51 | String referrer; |
52 | |
53 | FetchHeaders::Guard ; |
54 | ResourceResponse::CrossThreadData response; |
55 | ResponseBody responseBody; |
56 | uint64_t responseBodySize; |
57 | }; |
58 | |
59 | static CrossThreadRecordData toCrossThreadRecordData(const Record& record) |
60 | { |
61 | return CrossThreadRecordData { |
62 | record.identifier, |
63 | record.updateResponseCounter, |
64 | record.requestHeadersGuard, |
65 | record.request.isolatedCopy(), |
66 | record.options.isolatedCopy(), |
67 | record.referrer.isolatedCopy(), |
68 | record.responseHeadersGuard, |
69 | record.response.crossThreadData(), |
70 | isolatedResponseBody(record.responseBody), |
71 | record.responseBodySize |
72 | }; |
73 | } |
74 | |
75 | static Record fromCrossThreadRecordData(CrossThreadRecordData&& data) |
76 | { |
77 | return Record { |
78 | data.identifier, |
79 | data.updateResponseCounter, |
80 | data.requestHeadersGuard, |
81 | WTFMove(data.request), |
82 | WTFMove(data.options), |
83 | WTFMove(data.referrer), |
84 | data.responseHeadersGuard, |
85 | ResourceResponse::fromCrossThreadData(WTFMove(data.response)), |
86 | WTFMove(data.responseBody), |
87 | data.responseBodySize |
88 | }; |
89 | } |
90 | |
91 | static inline Vector<CrossThreadRecordData> recordsDataFromRecords(const Vector<Record>& records) |
92 | { |
93 | return WTF::map(records, toCrossThreadRecordData); |
94 | } |
95 | |
96 | static inline Expected<Vector<CrossThreadRecordData>, Error> recordsDataOrErrorFromRecords(const RecordsOrError& result) |
97 | { |
98 | if (!result.has_value()) |
99 | return makeUnexpected(result.error()); |
100 | |
101 | return recordsDataFromRecords(result.value()); |
102 | } |
103 | |
104 | static inline Vector<Record> recordsFromRecordsData(Vector<CrossThreadRecordData>&& recordsData) |
105 | { |
106 | return WTF::map(WTFMove(recordsData), fromCrossThreadRecordData); |
107 | } |
108 | |
109 | static inline RecordsOrError recordsOrErrorFromRecordsData(Expected<Vector<CrossThreadRecordData>, Error>&& recordsData) |
110 | { |
111 | if (!recordsData.has_value()) |
112 | return makeUnexpected(recordsData.error()); |
113 | return recordsFromRecordsData(WTFMove(recordsData.value())); |
114 | } |
115 | |
116 | Ref<WorkerCacheStorageConnection> WorkerCacheStorageConnection::create(WorkerGlobalScope& scope) |
117 | { |
118 | auto connection = adoptRef(*new WorkerCacheStorageConnection(scope)); |
119 | callOnMainThreadAndWait([workerThread = makeRef(scope.thread()), connection = connection.ptr()]() mutable { |
120 | connection->m_mainThreadConnection = workerThread->workerLoaderProxy().createCacheStorageConnection(); |
121 | }); |
122 | ASSERT(connection->m_mainThreadConnection); |
123 | return connection; |
124 | } |
125 | |
126 | WorkerCacheStorageConnection::WorkerCacheStorageConnection(WorkerGlobalScope& scope) |
127 | : m_scope(scope) |
128 | { |
129 | } |
130 | |
131 | WorkerCacheStorageConnection::~WorkerCacheStorageConnection() |
132 | { |
133 | if (m_mainThreadConnection) |
134 | callOnMainThread([mainThreadConnection = WTFMove(m_mainThreadConnection)]() mutable { }); |
135 | } |
136 | |
137 | void WorkerCacheStorageConnection::open(const ClientOrigin& origin, const String& cacheName, CacheIdentifierCallback&& callback) |
138 | { |
139 | uint64_t requestIdentifier = ++m_lastRequestIdentifier; |
140 | m_openAndRemoveCachePendingRequests.add(requestIdentifier, WTFMove(callback)); |
141 | |
142 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, origin = origin.isolatedCopy(), cacheName = cacheName.isolatedCopy()] () mutable { |
143 | mainThreadConnection->open(origin, cacheName, [workerThread = WTFMove(workerThread), requestIdentifier] (const CacheIdentifierOrError& result) mutable { |
144 | workerThread->runLoop().postTaskForMode([requestIdentifier, result] (auto& scope) mutable { |
145 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().openOrRemoveCompleted(requestIdentifier, result); |
146 | }, WorkerRunLoop::defaultMode()); |
147 | }); |
148 | }); |
149 | } |
150 | |
151 | void WorkerCacheStorageConnection::openOrRemoveCompleted(uint64_t requestIdentifier, const CacheIdentifierOrError& result) |
152 | { |
153 | if (auto callback = m_openAndRemoveCachePendingRequests.take(requestIdentifier)) |
154 | callback(result); |
155 | } |
156 | |
157 | void WorkerCacheStorageConnection::remove(uint64_t cacheIdentifier, CacheIdentifierCallback&& callback) |
158 | { |
159 | uint64_t requestIdentifier = ++m_lastRequestIdentifier; |
160 | m_openAndRemoveCachePendingRequests.add(requestIdentifier, WTFMove(callback)); |
161 | |
162 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier] () mutable { |
163 | mainThreadConnection->remove(cacheIdentifier, [workerThread = WTFMove(workerThread), requestIdentifier, cacheIdentifier] (const CacheIdentifierOrError& result) mutable { |
164 | ASSERT_UNUSED(cacheIdentifier, !result.has_value() || !result.value().identifier || result.value().identifier == cacheIdentifier); |
165 | workerThread->runLoop().postTaskForMode([requestIdentifier, result] (auto& scope) mutable { |
166 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().openOrRemoveCompleted(requestIdentifier, result); |
167 | }, WorkerRunLoop::defaultMode()); |
168 | }); |
169 | }); |
170 | } |
171 | |
172 | void WorkerCacheStorageConnection::retrieveCaches(const ClientOrigin& origin, uint64_t updateCounter, CacheInfosCallback&& callback) |
173 | { |
174 | uint64_t requestIdentifier = ++m_lastRequestIdentifier; |
175 | m_retrieveCachesPendingRequests.add(requestIdentifier, WTFMove(callback)); |
176 | |
177 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, origin = origin.isolatedCopy(), updateCounter] () mutable { |
178 | mainThreadConnection->retrieveCaches(origin, updateCounter, [workerThread = WTFMove(workerThread), requestIdentifier] (CacheInfosOrError&& result) mutable { |
179 | CacheInfosOrError isolatedResult; |
180 | if (!result.has_value()) |
181 | isolatedResult = WTFMove(result); |
182 | else |
183 | isolatedResult = result.value().isolatedCopy(); |
184 | |
185 | workerThread->runLoop().postTaskForMode([requestIdentifier, result = WTFMove(isolatedResult)] (auto& scope) mutable { |
186 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().retrieveCachesCompleted(requestIdentifier, WTFMove(result)); |
187 | }, WorkerRunLoop::defaultMode()); |
188 | }); |
189 | }); |
190 | } |
191 | |
192 | void WorkerCacheStorageConnection::retrieveCachesCompleted(uint64_t requestIdentifier, CacheInfosOrError&& result) |
193 | { |
194 | if (auto callback = m_retrieveCachesPendingRequests.take(requestIdentifier)) |
195 | callback(WTFMove(result)); |
196 | } |
197 | |
198 | void WorkerCacheStorageConnection::retrieveRecords(uint64_t cacheIdentifier, const URL& url, RecordsCallback&& callback) |
199 | { |
200 | uint64_t requestIdentifier = ++m_lastRequestIdentifier; |
201 | m_retrieveRecordsPendingRequests.add(requestIdentifier, WTFMove(callback)); |
202 | |
203 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier, url = url.isolatedCopy()]() mutable { |
204 | mainThreadConnection->retrieveRecords(cacheIdentifier, url, [workerThread = WTFMove(workerThread), requestIdentifier](RecordsOrError&& result) mutable { |
205 | workerThread->runLoop().postTaskForMode([result = recordsDataOrErrorFromRecords(result), requestIdentifier] (auto& scope) mutable { |
206 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().retrieveRecordsCompleted(requestIdentifier, recordsOrErrorFromRecordsData(WTFMove(result))); |
207 | }, WorkerRunLoop::defaultMode()); |
208 | }); |
209 | }); |
210 | } |
211 | |
212 | void WorkerCacheStorageConnection::retrieveRecordsCompleted(uint64_t requestIdentifier, RecordsOrError&& result) |
213 | { |
214 | if (auto callback = m_retrieveRecordsPendingRequests.take(requestIdentifier)) |
215 | callback(WTFMove(result)); |
216 | } |
217 | |
218 | void WorkerCacheStorageConnection::batchDeleteOperation(uint64_t cacheIdentifier, const ResourceRequest& request, CacheQueryOptions&& options, RecordIdentifiersCallback&& callback) |
219 | { |
220 | uint64_t requestIdentifier = ++m_lastRequestIdentifier; |
221 | m_batchDeleteAndPutPendingRequests.add(requestIdentifier, WTFMove(callback)); |
222 | |
223 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier, request = request.isolatedCopy(), options = options.isolatedCopy()]() mutable { |
224 | mainThreadConnection->batchDeleteOperation(cacheIdentifier, request, WTFMove(options), [workerThread = WTFMove(workerThread), requestIdentifier](RecordIdentifiersOrError&& result) mutable { |
225 | workerThread->runLoop().postTaskForMode([requestIdentifier, result = WTFMove(result)] (auto& scope) mutable { |
226 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().deleteRecordsCompleted(requestIdentifier, WTFMove(result)); |
227 | }, WorkerRunLoop::defaultMode()); |
228 | }); |
229 | }); |
230 | } |
231 | |
232 | void WorkerCacheStorageConnection::deleteRecordsCompleted(uint64_t requestIdentifier, Expected<Vector<uint64_t>, Error>&& result) |
233 | { |
234 | if (auto callback = m_batchDeleteAndPutPendingRequests.take(requestIdentifier)) |
235 | callback(WTFMove(result)); |
236 | } |
237 | |
238 | void WorkerCacheStorageConnection::batchPutOperation(uint64_t cacheIdentifier, Vector<DOMCacheEngine::Record>&& records, DOMCacheEngine::RecordIdentifiersCallback&& callback) |
239 | { |
240 | uint64_t requestIdentifier = ++m_lastRequestIdentifier; |
241 | m_batchDeleteAndPutPendingRequests.add(requestIdentifier, WTFMove(callback)); |
242 | |
243 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier, recordsData = recordsDataFromRecords(records)]() mutable { |
244 | mainThreadConnection->batchPutOperation(cacheIdentifier, recordsFromRecordsData(WTFMove(recordsData)), [workerThread = WTFMove(workerThread), requestIdentifier] (RecordIdentifiersOrError&& result) mutable { |
245 | workerThread->runLoop().postTaskForMode([requestIdentifier, result = WTFMove(result)] (auto& scope) mutable { |
246 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().putRecordsCompleted(requestIdentifier, WTFMove(result)); |
247 | }, WorkerRunLoop::defaultMode()); |
248 | }); |
249 | }); |
250 | } |
251 | |
252 | void WorkerCacheStorageConnection::putRecordsCompleted(uint64_t requestIdentifier, Expected<Vector<uint64_t>, Error>&& result) |
253 | { |
254 | if (auto callback = m_batchDeleteAndPutPendingRequests.take(requestIdentifier)) |
255 | callback(WTFMove(result)); |
256 | } |
257 | |
258 | void WorkerCacheStorageConnection::reference(uint64_t cacheIdentifier) |
259 | { |
260 | callOnMainThread([mainThreadConnection = m_mainThreadConnection, cacheIdentifier]() { |
261 | mainThreadConnection->reference(cacheIdentifier); |
262 | }); |
263 | } |
264 | |
265 | void WorkerCacheStorageConnection::dereference(uint64_t cacheIdentifier) |
266 | { |
267 | callOnMainThread([mainThreadConnection = m_mainThreadConnection, cacheIdentifier]() { |
268 | mainThreadConnection->dereference(cacheIdentifier); |
269 | }); |
270 | } |
271 | |
272 | void WorkerCacheStorageConnection::clearPendingRequests() |
273 | { |
274 | auto openAndRemoveCachePendingRequests = WTFMove(m_openAndRemoveCachePendingRequests); |
275 | for (auto& callback : openAndRemoveCachePendingRequests.values()) |
276 | callback(makeUnexpected(DOMCacheEngine::Error::Stopped)); |
277 | |
278 | auto retrieveCachesPendingRequests = WTFMove(m_retrieveCachesPendingRequests); |
279 | for (auto& callback : retrieveCachesPendingRequests.values()) |
280 | callback(makeUnexpected(DOMCacheEngine::Error::Stopped)); |
281 | |
282 | auto retrieveRecordsPendingRequests = WTFMove(m_retrieveRecordsPendingRequests); |
283 | for (auto& callback : retrieveRecordsPendingRequests.values()) |
284 | callback(makeUnexpected(DOMCacheEngine::Error::Stopped)); |
285 | |
286 | auto batchDeleteAndPutPendingRequests = WTFMove(m_batchDeleteAndPutPendingRequests); |
287 | for (auto& callback : batchDeleteAndPutPendingRequests.values()) |
288 | callback(makeUnexpected(DOMCacheEngine::Error::Stopped)); |
289 | } |
290 | |
291 | } // namespace WebCore |
292 | |