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 | Ref<WorkerCacheStorageConnection> WorkerCacheStorageConnection::create(WorkerGlobalScope& scope) |
92 | { |
93 | auto connection = adoptRef(*new WorkerCacheStorageConnection(scope)); |
94 | callOnMainThreadAndWait([workerThread = makeRef(scope.thread()), connection = connection.ptr()]() mutable { |
95 | connection->m_mainThreadConnection = workerThread->workerLoaderProxy().createCacheStorageConnection(); |
96 | }); |
97 | ASSERT(connection->m_mainThreadConnection); |
98 | return connection; |
99 | } |
100 | |
101 | WorkerCacheStorageConnection::WorkerCacheStorageConnection(WorkerGlobalScope& scope) |
102 | : m_scope(scope) |
103 | { |
104 | } |
105 | |
106 | WorkerCacheStorageConnection::~WorkerCacheStorageConnection() |
107 | { |
108 | if (m_mainThreadConnection) |
109 | callOnMainThread([mainThreadConnection = WTFMove(m_mainThreadConnection)]() mutable { }); |
110 | } |
111 | |
112 | void WorkerCacheStorageConnection::doOpen(uint64_t requestIdentifier, const ClientOrigin& origin, const String& cacheName) |
113 | { |
114 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, origin = origin.isolatedCopy(), cacheName = cacheName.isolatedCopy()] () mutable { |
115 | mainThreadConnection->open(origin, cacheName, [workerThread = WTFMove(workerThread), requestIdentifier] (const CacheIdentifierOrError& result) mutable { |
116 | workerThread->runLoop().postTaskForMode([requestIdentifier, result] (auto& scope) mutable { |
117 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().openCompleted(requestIdentifier, result); |
118 | }, WorkerRunLoop::defaultMode()); |
119 | }); |
120 | }); |
121 | } |
122 | |
123 | void WorkerCacheStorageConnection::doRemove(uint64_t requestIdentifier, uint64_t cacheIdentifier) |
124 | { |
125 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier] () mutable { |
126 | mainThreadConnection->remove(cacheIdentifier, [workerThread = WTFMove(workerThread), requestIdentifier, cacheIdentifier] (const CacheIdentifierOrError& result) mutable { |
127 | ASSERT_UNUSED(cacheIdentifier, !result.has_value() || !result.value().identifier || result.value().identifier == cacheIdentifier); |
128 | workerThread->runLoop().postTaskForMode([requestIdentifier, result] (auto& scope) mutable { |
129 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().removeCompleted(requestIdentifier, result); |
130 | }, WorkerRunLoop::defaultMode()); |
131 | }); |
132 | }); |
133 | } |
134 | |
135 | void WorkerCacheStorageConnection::doRetrieveCaches(uint64_t requestIdentifier, const ClientOrigin& origin, uint64_t updateCounter) |
136 | { |
137 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, origin = origin.isolatedCopy(), updateCounter] () mutable { |
138 | mainThreadConnection->retrieveCaches(origin, updateCounter, [workerThread = WTFMove(workerThread), requestIdentifier] (CacheInfosOrError&& result) mutable { |
139 | CacheInfosOrError isolatedResult; |
140 | if (!result.has_value()) |
141 | isolatedResult = WTFMove(result); |
142 | else |
143 | isolatedResult = result.value().isolatedCopy(); |
144 | |
145 | workerThread->runLoop().postTaskForMode([requestIdentifier, result = WTFMove(isolatedResult)] (auto& scope) mutable { |
146 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().updateCaches(requestIdentifier, WTFMove(result)); |
147 | }, WorkerRunLoop::defaultMode()); |
148 | }); |
149 | }); |
150 | } |
151 | |
152 | void WorkerCacheStorageConnection::reference(uint64_t cacheIdentifier) |
153 | { |
154 | callOnMainThread([mainThreadConnection = m_mainThreadConnection, cacheIdentifier]() { |
155 | mainThreadConnection->reference(cacheIdentifier); |
156 | }); |
157 | } |
158 | |
159 | void WorkerCacheStorageConnection::dereference(uint64_t cacheIdentifier) |
160 | { |
161 | callOnMainThread([mainThreadConnection = m_mainThreadConnection, cacheIdentifier]() { |
162 | mainThreadConnection->dereference(cacheIdentifier); |
163 | }); |
164 | } |
165 | |
166 | static inline Vector<CrossThreadRecordData> recordsDataFromRecords(const Vector<Record>& records) |
167 | { |
168 | return WTF::map(records, toCrossThreadRecordData); |
169 | } |
170 | |
171 | static inline Expected<Vector<CrossThreadRecordData>, Error> recordsDataOrErrorFromRecords(const RecordsOrError& result) |
172 | { |
173 | if (!result.has_value()) |
174 | return makeUnexpected(result.error()); |
175 | |
176 | return recordsDataFromRecords(result.value()); |
177 | } |
178 | |
179 | static inline Vector<Record> recordsFromRecordsData(Vector<CrossThreadRecordData>&& recordsData) |
180 | { |
181 | return WTF::map(WTFMove(recordsData), fromCrossThreadRecordData); |
182 | } |
183 | |
184 | static inline RecordsOrError recordsOrErrorFromRecordsData(Expected<Vector<CrossThreadRecordData>, Error>&& recordsData) |
185 | { |
186 | if (!recordsData.has_value()) |
187 | return makeUnexpected(recordsData.error()); |
188 | return recordsFromRecordsData(WTFMove(recordsData.value())); |
189 | } |
190 | |
191 | void WorkerCacheStorageConnection::doRetrieveRecords(uint64_t requestIdentifier, uint64_t cacheIdentifier, const URL& url) |
192 | { |
193 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier, url = url.isolatedCopy()]() mutable { |
194 | mainThreadConnection->retrieveRecords(cacheIdentifier, url, [workerThread = WTFMove(workerThread), requestIdentifier](RecordsOrError&& result) mutable { |
195 | workerThread->runLoop().postTaskForMode([result = recordsDataOrErrorFromRecords(result), requestIdentifier] (auto& scope) mutable { |
196 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().updateRecords(requestIdentifier, recordsOrErrorFromRecordsData(WTFMove(result))); |
197 | }, WorkerRunLoop::defaultMode()); |
198 | }); |
199 | }); |
200 | } |
201 | |
202 | void WorkerCacheStorageConnection::doBatchDeleteOperation(uint64_t requestIdentifier, uint64_t cacheIdentifier, const ResourceRequest& request, CacheQueryOptions&& options) |
203 | { |
204 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier, request = request.isolatedCopy(), options = options.isolatedCopy()]() mutable { |
205 | mainThreadConnection->batchDeleteOperation(cacheIdentifier, request, WTFMove(options), [workerThread = WTFMove(workerThread), requestIdentifier](RecordIdentifiersOrError&& result) mutable { |
206 | workerThread->runLoop().postTaskForMode([requestIdentifier, result = WTFMove(result)] (auto& scope) mutable { |
207 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().deleteRecordsCompleted(requestIdentifier, WTFMove(result)); |
208 | }, WorkerRunLoop::defaultMode()); |
209 | }); |
210 | }); |
211 | } |
212 | |
213 | void WorkerCacheStorageConnection::doBatchPutOperation(uint64_t requestIdentifier, uint64_t cacheIdentifier, Vector<Record>&& records) |
214 | { |
215 | callOnMainThread([workerThread = makeRef(m_scope.thread()), mainThreadConnection = m_mainThreadConnection, requestIdentifier, cacheIdentifier, recordsData = recordsDataFromRecords(records)]() mutable { |
216 | mainThreadConnection->batchPutOperation(cacheIdentifier, recordsFromRecordsData(WTFMove(recordsData)), [workerThread = WTFMove(workerThread), requestIdentifier] (RecordIdentifiersOrError&& result) mutable { |
217 | workerThread->runLoop().postTaskForMode([requestIdentifier, result = WTFMove(result)] (auto& scope) mutable { |
218 | downcast<WorkerGlobalScope>(scope).cacheStorageConnection().putRecordsCompleted(requestIdentifier, WTFMove(result)); |
219 | }, WorkerRunLoop::defaultMode()); |
220 | }); |
221 | }); |
222 | } |
223 | |
224 | } // namespace WebCore |
225 | |