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