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
40namespace WebCore {
41using namespace WebCore::DOMCacheEngine;
42
43struct CrossThreadRecordData {
44 uint64_t identifier;
45 uint64_t updateResponseCounter;
46
47 FetchHeaders::Guard requestHeadersGuard;
48 ResourceRequest request;
49
50 FetchOptions options;
51 String referrer;
52
53 FetchHeaders::Guard responseHeadersGuard;
54 ResourceResponse::CrossThreadData response;
55 ResponseBody responseBody;
56 uint64_t responseBodySize;
57};
58
59static 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
75static 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
91Ref<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
101WorkerCacheStorageConnection::WorkerCacheStorageConnection(WorkerGlobalScope& scope)
102 : m_scope(scope)
103{
104}
105
106WorkerCacheStorageConnection::~WorkerCacheStorageConnection()
107{
108 if (m_mainThreadConnection)
109 callOnMainThread([mainThreadConnection = WTFMove(m_mainThreadConnection)]() mutable { });
110}
111
112void 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
123void 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
135void 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
152void WorkerCacheStorageConnection::reference(uint64_t cacheIdentifier)
153{
154 callOnMainThread([mainThreadConnection = m_mainThreadConnection, cacheIdentifier]() {
155 mainThreadConnection->reference(cacheIdentifier);
156 });
157}
158
159void WorkerCacheStorageConnection::dereference(uint64_t cacheIdentifier)
160{
161 callOnMainThread([mainThreadConnection = m_mainThreadConnection, cacheIdentifier]() {
162 mainThreadConnection->dereference(cacheIdentifier);
163 });
164}
165
166static inline Vector<CrossThreadRecordData> recordsDataFromRecords(const Vector<Record>& records)
167{
168 return WTF::map(records, toCrossThreadRecordData);
169}
170
171static 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
179static inline Vector<Record> recordsFromRecordsData(Vector<CrossThreadRecordData>&& recordsData)
180{
181 return WTF::map(WTFMove(recordsData), fromCrossThreadRecordData);
182}
183
184static 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
191void 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
202void 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
213void 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