Add support for configuring WebsiteDatastore service worker and cache storage path
[WebKit-https.git] / Source / WebKit / UIProcess / API / Cocoa / WKWebsiteDataStore.mm
1 /*
2  * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WKWebsiteDataStoreInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIString.h"
32 #import "WKHTTPCookieStoreInternal.h"
33 #import "WKNSArray.h"
34 #import "WKWebsiteDataRecordInternal.h"
35 #import "WebResourceLoadStatisticsStore.h"
36 #import "WebResourceLoadStatisticsTelemetry.h"
37 #import "WebsiteDataFetchOption.h"
38 #import "_WKWebsiteDataStoreConfiguration.h"
39 #import <WebCore/URL.h>
40 #import <wtf/BlockPtr.h>
41
42 using namespace WebCore;
43
44 @implementation WKWebsiteDataStore
45
46 + (WKWebsiteDataStore *)defaultDataStore
47 {
48     return WebKit::wrapper(API::WebsiteDataStore::defaultDataStore().get());
49 }
50
51 + (WKWebsiteDataStore *)nonPersistentDataStore
52 {
53     return [WebKit::wrapper(API::WebsiteDataStore::createNonPersistentDataStore().leakRef()) autorelease];
54 }
55
56 - (void)dealloc
57 {
58     _websiteDataStore->API::WebsiteDataStore::~WebsiteDataStore();
59
60     [super dealloc];
61 }
62
63 + (BOOL)supportsSecureCoding
64 {
65     return YES;
66 }
67
68 - (instancetype)initWithCoder:(NSCoder *)coder
69 {
70     if (!(self = [super init]))
71         return nil;
72
73     RetainPtr<WKWebsiteDataStore> dataStore;
74     if ([coder decodeBoolForKey:@"isDefaultDataStore"])
75         dataStore = [WKWebsiteDataStore defaultDataStore];
76     else
77         dataStore = [WKWebsiteDataStore nonPersistentDataStore];
78
79     [self release];
80
81     return dataStore.leakRef();
82 }
83
84 - (void)encodeWithCoder:(NSCoder *)coder
85 {
86     if (self == [WKWebsiteDataStore defaultDataStore]) {
87         [coder encodeBool:YES forKey:@"isDefaultDataStore"];
88         return;
89     }
90
91     ASSERT(!self.persistent);
92 }
93
94 - (BOOL)isPersistent
95 {
96     return _websiteDataStore->isPersistent();
97 }
98
99 + (NSSet *)allWebsiteDataTypes
100 {
101     static dispatch_once_t onceToken;
102     static NSSet *allWebsiteDataTypes;
103     dispatch_once(&onceToken, ^{
104         allWebsiteDataTypes = [[NSSet alloc] initWithArray:@[ WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeFetchCache, WKWebsiteDataTypeMemoryCache, WKWebsiteDataTypeOfflineWebApplicationCache, WKWebsiteDataTypeCookies, WKWebsiteDataTypeSessionStorage, WKWebsiteDataTypeLocalStorage, WKWebsiteDataTypeIndexedDBDatabases, WKWebsiteDataTypeServiceWorkerRegistrations, WKWebsiteDataTypeWebSQLDatabases ]];
105     });
106
107     return allWebsiteDataTypes;
108 }
109
110 - (WKHTTPCookieStore *)httpCookieStore
111 {
112     return WebKit::wrapper(_websiteDataStore->httpCookieStore());
113 }
114
115 static WallTime toSystemClockTime(NSDate *date)
116 {
117     ASSERT(date);
118     return WallTime::fromRawSeconds(date.timeIntervalSince1970);
119 }
120
121 - (void)fetchDataRecordsOfTypes:(NSSet *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
122 {
123     [self _fetchDataRecordsOfTypes:dataTypes withOptions:0 completionHandler:completionHandler];
124 }
125
126 - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler
127 {
128     auto completionHandlerCopy = makeBlockPtr(completionHandler);
129     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toSystemClockTime(date ? date : [NSDate distantPast]), [completionHandlerCopy] {
130         completionHandlerCopy();
131     });
132 }
133
134 static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecords)
135 {
136     Vector<WebKit::WebsiteDataRecord> result;
137
138     for (WKWebsiteDataRecord *dataRecord in dataRecords)
139         result.append(dataRecord->_websiteDataRecord->websiteDataRecord());
140
141     return result;
142 }
143
144 - (void)removeDataOfTypes:(NSSet *)dataTypes forDataRecords:(NSArray *)dataRecords completionHandler:(void (^)(void))completionHandler
145 {
146     auto completionHandlerCopy = makeBlockPtr(completionHandler);
147
148     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toWebsiteDataRecords(dataRecords), [completionHandlerCopy] {
149         completionHandlerCopy();
150     });
151 }
152
153 #pragma mark WKObject protocol implementation
154
155 - (API::Object&)_apiObject
156 {
157     return *_websiteDataStore;
158 }
159
160 @end
161
162 @implementation WKWebsiteDataStore (WKPrivate)
163
164 + (NSSet<NSString *> *)_allWebsiteDataTypesIncludingPrivate
165 {
166     static dispatch_once_t onceToken;
167     static NSSet *allWebsiteDataTypes;
168     dispatch_once(&onceToken, ^ {
169         auto *privateTypes = @[_WKWebsiteDataTypeHSTSCache, _WKWebsiteDataTypeMediaKeys, _WKWebsiteDataTypeSearchFieldRecentSearches, _WKWebsiteDataTypeResourceLoadStatistics, _WKWebsiteDataTypeCredentials
170 #if !TARGET_OS_IPHONE
171         , _WKWebsiteDataTypePlugInData
172 #endif
173         ];
174
175         allWebsiteDataTypes = [[[self allWebsiteDataTypes] setByAddingObjectsFromArray:privateTypes] retain];
176     });
177
178     return allWebsiteDataTypes;
179 }
180
181 + (BOOL)_defaultDataStoreExists
182 {
183     return API::WebsiteDataStore::defaultDataStoreExists();
184 }
185
186 - (instancetype)_initWithConfiguration:(_WKWebsiteDataStoreConfiguration *)configuration
187 {
188     if (!(self = [super init]))
189         return nil;
190
191     auto config = API::WebsiteDataStore::defaultDataStoreConfiguration();
192
193     if (configuration._webStorageDirectory)
194         config.localStorageDirectory = configuration._webStorageDirectory.path;
195     if (configuration._webSQLDatabaseDirectory)
196         config.webSQLDatabaseDirectory = configuration._webSQLDatabaseDirectory.path;
197     if (configuration._indexedDBDatabaseDirectory)
198         config.indexedDBDatabaseDirectory = configuration._indexedDBDatabaseDirectory.path;
199     if (configuration._cookieStorageFile)
200         config.cookieStorageFile = configuration._cookieStorageFile.path;
201     if (configuration._resourceLoadStatisticsDirectory)
202         config.resourceLoadStatisticsDirectory = configuration._resourceLoadStatisticsDirectory.path;
203     if (configuration._cacheStorageDirectory)
204         config.cacheStorageDirectory = configuration._cacheStorageDirectory.path;
205     if (configuration._serviceWorkerRegistrationDirectory)
206         config.serviceWorkerRegistrationDirectory = configuration._serviceWorkerRegistrationDirectory.path;
207
208     API::Object::constructInWrapper<API::WebsiteDataStore>(self, config, PAL::SessionID::generatePersistentSessionID());
209
210     return self;
211 }
212
213 - (void)_fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes withOptions:(_WKWebsiteDataStoreFetchOptions)options completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
214 {
215     auto completionHandlerCopy = makeBlockPtr(completionHandler);
216
217     OptionSet<WebKit::WebsiteDataFetchOption> fetchOptions;
218     if (options & _WKWebsiteDataStoreFetchOptionComputeSizes)
219         fetchOptions |= WebKit::WebsiteDataFetchOption::ComputeSizes;
220
221     _websiteDataStore->websiteDataStore().fetchData(WebKit::toWebsiteDataTypes(dataTypes), fetchOptions, [completionHandlerCopy = WTFMove(completionHandlerCopy)](auto websiteDataRecords) {
222         Vector<RefPtr<API::Object>> elements;
223         elements.reserveInitialCapacity(websiteDataRecords.size());
224
225         for (auto& websiteDataRecord : websiteDataRecords)
226             elements.uncheckedAppend(API::WebsiteDataRecord::create(WTFMove(websiteDataRecord)));
227
228         completionHandlerCopy(wrapper(API::Array::create(WTFMove(elements))));
229     });
230 }
231
232 - (BOOL)_resourceLoadStatisticsEnabled
233 {
234     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsEnabled();
235 }
236
237 - (void)_setResourceLoadStatisticsEnabled:(BOOL)enabled
238 {
239     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsEnabled(enabled);
240 }
241
242 - (BOOL)_resourceLoadStatisticsDebugMode
243 {
244     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsDebugMode();
245 }
246
247 - (void)_setResourceLoadStatisticsDebugMode:(BOOL)enabled
248 {
249     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsDebugMode(enabled);
250 }
251
252 - (NSUInteger)_cacheStoragePerOriginQuota
253 {
254     return _websiteDataStore->websiteDataStore().cacheStoragePerOriginQuota();
255 }
256
257 - (void)_setCacheStoragePerOriginQuota:(NSUInteger)size
258 {
259     _websiteDataStore->websiteDataStore().setCacheStoragePerOriginQuota(size);
260 }
261
262 - (NSString *)_cacheStorageDirectory
263 {
264     return _websiteDataStore->websiteDataStore().cacheStorageDirectory();
265 }
266
267 - (void)_setCacheStorageDirectory:(NSString *)directory
268 {
269     _websiteDataStore->websiteDataStore().setCacheStorageDirectory(directory);
270 }
271
272 - (NSString *)_serviceWorkerRegistrationDirectory
273 {
274     return _websiteDataStore->websiteDataStore().serviceWorkerRegistrationDirectory();
275 }
276
277 - (void)_setServiceWorkerRegistrationDirectory:(NSString *)directory
278 {
279     _websiteDataStore->websiteDataStore().setServiceWorkerRegistrationDirectory(directory);
280 }
281
282 - (void)_setBoundInterfaceIdentifier:(NSString *)identifier
283 {
284     _websiteDataStore->websiteDataStore().setBoundInterfaceIdentifier(identifier);
285 }
286
287 - (NSString *)_boundInterfaceIdentifier
288 {
289     return _websiteDataStore->websiteDataStore().boundInterfaceIdentifier();
290 }
291
292 - (void)_setAllowsCellularAccess:(BOOL)allows
293 {
294     _websiteDataStore->websiteDataStore().setAllowsCellularAccess(allows ? WebKit::AllowsCellularAccess::Yes : WebKit::AllowsCellularAccess::No);
295 }
296
297 - (BOOL)_allowsCellularAccess
298 {
299     return _websiteDataStore->websiteDataStore().allowsCellularAccess() == WebKit::AllowsCellularAccess::Yes;
300 }
301
302 - (void)_resourceLoadStatisticsSetShouldSubmitTelemetry:(BOOL)value
303 {
304     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
305     if (!store)
306         return;
307
308     store->setShouldSubmitTelemetry(value);
309 }
310
311 - (void)_setResourceLoadStatisticsTestingCallback:(void (^)(WKWebsiteDataStore *, NSString *))callback
312 {
313     if (callback) {
314         _websiteDataStore->websiteDataStore().enableResourceLoadStatisticsAndSetTestingCallback([callback = makeBlockPtr(callback), self](const String& event) {
315             callback(self, (NSString *)event);
316         });
317         return;
318     }
319
320     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
321     if (!store)
322         return;
323
324     store->setStatisticsTestingCallback(nullptr);
325 }
326
327 + (void)_allowWebsiteDataRecordsForAllOrigins
328 {
329     WebKit::WebsiteDataStore::allowWebsiteDataRecordsForAllOrigins();
330 }
331
332 - (void)_getAllStorageAccessEntries:(void (^)(NSArray<NSString *> *domains))completionHandler
333 {
334     _websiteDataStore->websiteDataStore().getAllStorageAccessEntries([completionHandler = makeBlockPtr(completionHandler)](auto domains) {
335         Vector<RefPtr<API::Object>> apiDomains;
336         apiDomains.reserveInitialCapacity(domains.size());
337         for (auto& domain : domains)
338             apiDomains.uncheckedAppend(API::String::create(domain));
339
340         completionHandler(wrapper(API::Array::create(WTFMove(apiDomains))));
341     });
342 }
343
344 @end
345
346 #endif // WK_API_ENABLED