29c9fad1f5322051adbad47fde3de750e1a0d5db
[WebKit-https.git] / Source / WebCore / Modules / cache / WorkerCacheStorageConnection.cpp
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 "Document.h"
33 #include "Page.h"
34 #include "WorkerGlobalScope.h"
35 #include "WorkerLoaderProxy.h"
36 #include "WorkerRunLoop.h"
37 #include "WorkerThread.h"
38
39 namespace WebCore {
40
41 struct CrossThreadRecordData {
42     uint64_t identifier;
43
44     FetchHeaders::Guard requestHeadersGuard;
45     ResourceRequest request;
46
47     FetchOptions options;
48     String referrer;
49
50     FetchHeaders::Guard responseHeadersGuard;
51     ResourceResponse::CrossThreadData response;
52 };
53
54 static CrossThreadRecordData toCrossThreadRecordData(const CacheStorageConnection::Record& record)
55 {
56     return CrossThreadRecordData {
57         record.identifier,
58         record.requestHeadersGuard,
59         record.request.isolatedCopy(),
60         record.options.isolatedCopy(),
61         record.referrer.isolatedCopy(),
62         record.responseHeadersGuard,
63         record.response.crossThreadData()
64     };
65 }
66
67 static CacheStorageConnection::Record fromCrossThreadRecordData(CrossThreadRecordData&& data)
68 {
69     return CacheStorageConnection::Record {
70         data.identifier,
71         data.requestHeadersGuard,
72         WTFMove(data.request),
73         WTFMove(data.options),
74         WTFMove(data.referrer),
75         data.responseHeadersGuard,
76         ResourceResponse::fromCrossThreadData(WTFMove(data.response))
77     };
78 }
79
80 Ref<WorkerCacheStorageConnection> WorkerCacheStorageConnection::create(WorkerGlobalScope& scope)
81 {
82     auto connection = adoptRef(*new WorkerCacheStorageConnection(scope));
83     connection->m_proxy.postTaskToLoader([protectedConnection = makeRef(connection.get())](ScriptExecutionContext& context) mutable {
84         ASSERT(isMainThread());
85         Document& document = downcast<Document>(context);
86
87         ASSERT(document.page());
88         protectedConnection->m_mainThreadConnection = document.page()->cacheStorageProvider().createCacheStorageConnection(document.page()->sessionID());
89     });
90     return connection;
91 }
92
93 WorkerCacheStorageConnection::WorkerCacheStorageConnection(WorkerGlobalScope& scope)
94     : m_scope(scope)
95     , m_proxy(m_scope.thread().workerLoaderProxy())
96     , m_taskMode(WorkerRunLoop::defaultMode().isolatedCopy())
97 {
98 }
99
100 WorkerCacheStorageConnection::~WorkerCacheStorageConnection()
101 {
102     if (m_mainThreadConnection)
103         m_proxy.postTaskToLoader([mainThreadConnection = WTFMove(m_mainThreadConnection)](ScriptExecutionContext&) mutable { });
104 }
105
106 void WorkerCacheStorageConnection::doOpen(uint64_t requestIdentifier, const String& origin, const String& cacheName)
107 {
108     m_proxy.postTaskToLoader([this, protectedThis = makeRef(*this), requestIdentifier, origin = origin.isolatedCopy(), cacheName = cacheName.isolatedCopy()](ScriptExecutionContext&) mutable {
109         ASSERT(isMainThread());
110         ASSERT(m_mainThreadConnection);
111
112         m_mainThreadConnection->open(origin, cacheName, [this, protectedThis = WTFMove(protectedThis), requestIdentifier](uint64_t cacheIdentifier, Error error) mutable {
113             m_proxy.postTaskForModeToWorkerGlobalScope([this, error, cacheIdentifier, protectedThis = WTFMove(protectedThis), requestIdentifier](ScriptExecutionContext& context) mutable {
114                 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
115                 openCompleted(requestIdentifier, cacheIdentifier, error);
116             }, m_taskMode);
117         });
118     });
119 }
120
121 void WorkerCacheStorageConnection::doRemove(uint64_t requestIdentifier, uint64_t cacheIdentifier)
122 {
123     m_proxy.postTaskToLoader([this, protectedThis = makeRef(*this), requestIdentifier, cacheIdentifier](ScriptExecutionContext&) mutable {
124         ASSERT(isMainThread());
125         ASSERT(m_mainThreadConnection);
126
127         m_mainThreadConnection->remove(cacheIdentifier, [this, protectedThis = WTFMove(protectedThis), requestIdentifier, cacheIdentifier](uint64_t removedCacheIdentifier, Error error) mutable {
128             ASSERT_UNUSED(removedCacheIdentifier, removedCacheIdentifier == cacheIdentifier);
129             m_proxy.postTaskForModeToWorkerGlobalScope([this, protectedThis = WTFMove(protectedThis), requestIdentifier, cacheIdentifier, error](ScriptExecutionContext& context) mutable {
130                 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
131                 removeCompleted(requestIdentifier, cacheIdentifier, error);
132             }, m_taskMode);
133         });
134     });
135 }
136
137 void WorkerCacheStorageConnection::doRetrieveCaches(uint64_t requestIdentifier, const String& origin)
138 {
139     m_proxy.postTaskToLoader([this, protectedThis = makeRef(*this), requestIdentifier, origin = origin.isolatedCopy()](ScriptExecutionContext&) mutable {
140         ASSERT(isMainThread());
141         ASSERT(m_mainThreadConnection);
142
143         m_mainThreadConnection->retrieveCaches(origin, [this, protectedThis = WTFMove(protectedThis), requestIdentifier](const Vector<CacheInfo>& caches) mutable {
144             Vector<CacheInfo> isolatedCaches;
145             isolatedCaches.reserveInitialCapacity(caches.size());
146             for (const auto& cache : caches)
147                 isolatedCaches.uncheckedAppend(CacheInfo { cache.identifier, cache.name.isolatedCopy() });
148
149             m_proxy.postTaskForModeToWorkerGlobalScope([this, protectedThis = WTFMove(protectedThis), caches = WTFMove(isolatedCaches), requestIdentifier](ScriptExecutionContext& context) mutable {
150                 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
151                 updateCaches(requestIdentifier, WTFMove(caches));
152             }, m_taskMode);
153         });
154     });
155 }
156
157 static inline Vector<CrossThreadRecordData> recordsDataFromRecords(const Vector<CacheStorageConnection::Record>& records)
158 {
159     Vector<CrossThreadRecordData> recordsData;
160     recordsData.reserveInitialCapacity(records.size());
161     for (const auto& record : records)
162         recordsData.uncheckedAppend(toCrossThreadRecordData(record));
163     return recordsData;
164 }
165
166 static inline Vector<CacheStorageConnection::Record> recordsFromRecordsData(Vector<CrossThreadRecordData>&& recordsData)
167 {
168     Vector<CacheStorageConnection::Record> records;
169     records.reserveInitialCapacity(recordsData.size());
170     for (auto& recordData : recordsData)
171         records.uncheckedAppend(fromCrossThreadRecordData(WTFMove(recordData)));
172     return records;
173 }
174
175 void WorkerCacheStorageConnection::doRetrieveRecords(uint64_t requestIdentifier, uint64_t cacheIdentifier)
176 {
177     m_proxy.postTaskToLoader([this, protectedThis = makeRef(*this), requestIdentifier, cacheIdentifier](ScriptExecutionContext&) mutable {
178         ASSERT(isMainThread());
179         ASSERT(m_mainThreadConnection);
180
181         m_mainThreadConnection->retrieveRecords(cacheIdentifier, [this, protectedThis = WTFMove(protectedThis), requestIdentifier](Vector<Record>&& records) mutable {
182             m_proxy.postTaskForModeToWorkerGlobalScope([this, protectedThis = WTFMove(protectedThis), recordsData = recordsDataFromRecords(records), requestIdentifier](ScriptExecutionContext& context) mutable {
183                 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
184                 updateRecords(requestIdentifier, recordsFromRecordsData(WTFMove(recordsData)));
185             }, m_taskMode);
186         });
187     });
188 }
189
190 void WorkerCacheStorageConnection::doBatchDeleteOperation(uint64_t requestIdentifier, uint64_t cacheIdentifier, const ResourceRequest& request, CacheQueryOptions&& options)
191 {
192     m_proxy.postTaskToLoader([this, protectedThis = makeRef(*this), requestIdentifier, cacheIdentifier, request = request.isolatedCopy(), options = options.isolatedCopy()](ScriptExecutionContext&) mutable {
193         ASSERT(isMainThread());
194         ASSERT(m_mainThreadConnection);
195
196         m_mainThreadConnection->batchDeleteOperation(cacheIdentifier, request, WTFMove(options), [this, protectedThis = WTFMove(protectedThis), requestIdentifier](Vector<uint64_t>&& records, Error error) mutable {
197
198             m_proxy.postTaskForModeToWorkerGlobalScope([this, protectedThis = WTFMove(protectedThis), records = WTFMove(records), error, requestIdentifier](ScriptExecutionContext& context) mutable {
199                 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
200                 deleteRecordsCompleted(requestIdentifier, WTFMove(records), error);
201             }, m_taskMode);
202         });
203     });
204 }
205
206 void WorkerCacheStorageConnection::doBatchPutOperation(uint64_t requestIdentifier, uint64_t cacheIdentifier, Vector<Record>&& records)
207 {
208     m_proxy.postTaskToLoader([this, protectedThis = makeRef(*this), requestIdentifier, cacheIdentifier, recordsData = recordsDataFromRecords(records)](ScriptExecutionContext&) mutable {
209         ASSERT(isMainThread());
210         ASSERT(m_mainThreadConnection);
211
212         m_mainThreadConnection->batchPutOperation(cacheIdentifier, recordsFromRecordsData(WTFMove(recordsData)), [this, protectedThis = WTFMove(protectedThis), requestIdentifier](Vector<uint64_t>&& records, Error error) mutable {
213
214             m_proxy.postTaskForModeToWorkerGlobalScope([this, protectedThis = WTFMove(protectedThis), records = WTFMove(records), error, requestIdentifier](ScriptExecutionContext& context) mutable {
215                 ASSERT_UNUSED(context, context.isWorkerGlobalScope());
216                 putRecordsCompleted(requestIdentifier, WTFMove(records), error);
217             }, m_taskMode);
218         });
219     });
220 }
221
222 } // namespace WebCore