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