74bf659abd6c5e81f8cb7deb3f5720813ce0c43b
[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 "WKWebViewInternal.h"
35 #import "WKWebsiteDataRecordInternal.h"
36 #import "WebPageProxy.h"
37 #import "WebResourceLoadStatisticsStore.h"
38 #import "WebResourceLoadStatisticsTelemetry.h"
39 #import "WebsiteDataFetchOption.h"
40 #import "_WKWebsiteDataStoreConfiguration.h"
41 #import <WebKit/ServiceWorkerProcessProxy.h>
42 #import <wtf/BlockPtr.h>
43 #import <wtf/URL.h>
44
45 @implementation WKWebsiteDataStore
46
47 + (WKWebsiteDataStore *)defaultDataStore
48 {
49     return wrapper(API::WebsiteDataStore::defaultDataStore());
50 }
51
52 + (WKWebsiteDataStore *)nonPersistentDataStore
53 {
54     return wrapper(API::WebsiteDataStore::createNonPersistentDataStore());
55 }
56
57 - (void)dealloc
58 {
59     _websiteDataStore->API::WebsiteDataStore::~WebsiteDataStore();
60
61     [super dealloc];
62 }
63
64 + (BOOL)supportsSecureCoding
65 {
66     return YES;
67 }
68
69 - (instancetype)initWithCoder:(NSCoder *)coder
70 {
71     if (!(self = [super init]))
72         return nil;
73
74     RetainPtr<WKWebsiteDataStore> dataStore;
75     if ([coder decodeBoolForKey:@"isDefaultDataStore"])
76         dataStore = [WKWebsiteDataStore defaultDataStore];
77     else
78         dataStore = [WKWebsiteDataStore nonPersistentDataStore];
79
80     [self release];
81
82     return dataStore.leakRef();
83 }
84
85 - (void)encodeWithCoder:(NSCoder *)coder
86 {
87     if (self == [WKWebsiteDataStore defaultDataStore]) {
88         [coder encodeBool:YES forKey:@"isDefaultDataStore"];
89         return;
90     }
91
92     ASSERT(!self.persistent);
93 }
94
95 - (BOOL)isPersistent
96 {
97     return _websiteDataStore->isPersistent();
98 }
99
100 + (NSSet *)allWebsiteDataTypes
101 {
102     static dispatch_once_t onceToken;
103     static NSSet *allWebsiteDataTypes;
104     dispatch_once(&onceToken, ^{
105         allWebsiteDataTypes = [[NSSet alloc] initWithArray:@[ WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeFetchCache, WKWebsiteDataTypeMemoryCache, WKWebsiteDataTypeOfflineWebApplicationCache, WKWebsiteDataTypeCookies, WKWebsiteDataTypeSessionStorage, WKWebsiteDataTypeLocalStorage, WKWebsiteDataTypeIndexedDBDatabases, WKWebsiteDataTypeServiceWorkerRegistrations, WKWebsiteDataTypeWebSQLDatabases ]];
106     });
107
108     return allWebsiteDataTypes;
109 }
110
111 - (WKHTTPCookieStore *)httpCookieStore
112 {
113     return wrapper(_websiteDataStore->httpCookieStore());
114 }
115
116 static WallTime toSystemClockTime(NSDate *date)
117 {
118     ASSERT(date);
119     return WallTime::fromRawSeconds(date.timeIntervalSince1970);
120 }
121
122 - (void)fetchDataRecordsOfTypes:(NSSet *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
123 {
124     [self _fetchDataRecordsOfTypes:dataTypes withOptions:0 completionHandler:completionHandler];
125 }
126
127 - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler
128 {
129     auto completionHandlerCopy = makeBlockPtr(completionHandler);
130     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toSystemClockTime(date ? date : [NSDate distantPast]), [completionHandlerCopy] {
131         completionHandlerCopy();
132     });
133 }
134
135 static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecords)
136 {
137     Vector<WebKit::WebsiteDataRecord> result;
138
139     for (WKWebsiteDataRecord *dataRecord in dataRecords)
140         result.append(dataRecord->_websiteDataRecord->websiteDataRecord());
141
142     return result;
143 }
144
145 - (void)removeDataOfTypes:(NSSet *)dataTypes forDataRecords:(NSArray *)dataRecords completionHandler:(void (^)(void))completionHandler
146 {
147     auto completionHandlerCopy = makeBlockPtr(completionHandler);
148
149     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toWebsiteDataRecords(dataRecords), [completionHandlerCopy] {
150         completionHandlerCopy();
151     });
152 }
153
154 #pragma mark WKObject protocol implementation
155
156 - (API::Object&)_apiObject
157 {
158     return *_websiteDataStore;
159 }
160
161 @end
162
163 @implementation WKWebsiteDataStore (WKPrivate)
164
165 + (NSSet<NSString *> *)_allWebsiteDataTypesIncludingPrivate
166 {
167     static dispatch_once_t onceToken;
168     static NSSet *allWebsiteDataTypes;
169     dispatch_once(&onceToken, ^ {
170         auto *privateTypes = @[_WKWebsiteDataTypeHSTSCache, _WKWebsiteDataTypeMediaKeys, _WKWebsiteDataTypeSearchFieldRecentSearches, _WKWebsiteDataTypeResourceLoadStatistics, _WKWebsiteDataTypeCredentials
171 #if !TARGET_OS_IPHONE
172         , _WKWebsiteDataTypePlugInData
173 #endif
174         ];
175
176         allWebsiteDataTypes = [[[self allWebsiteDataTypes] setByAddingObjectsFromArray:privateTypes] retain];
177     });
178
179     return allWebsiteDataTypes;
180 }
181
182 + (BOOL)_defaultDataStoreExists
183 {
184     return API::WebsiteDataStore::defaultDataStoreExists();
185 }
186
187 + (void)_deleteDefaultDataStoreForTesting
188 {
189     return API::WebsiteDataStore::deleteDefaultDataStoreForTesting();
190 }
191
192 - (instancetype)_initWithConfiguration:(_WKWebsiteDataStoreConfiguration *)configuration
193 {
194     if (!(self = [super init]))
195         return nil;
196
197     auto config = API::WebsiteDataStore::defaultDataStoreConfiguration();
198
199     if (configuration._webStorageDirectory)
200         config->setLocalStorageDirectory(configuration._webStorageDirectory.path);
201     if (configuration._webSQLDatabaseDirectory)
202         config->setWebSQLDatabaseDirectory(configuration._webSQLDatabaseDirectory.path);
203     if (configuration._indexedDBDatabaseDirectory)
204         config->setIndexedDBDatabaseDirectory(configuration._indexedDBDatabaseDirectory.path);
205     if (configuration._cookieStorageFile)
206         config->setCookieStorageFile(configuration._cookieStorageFile.path);
207     if (configuration._resourceLoadStatisticsDirectory)
208         config->setResourceLoadStatisticsDirectory(configuration._resourceLoadStatisticsDirectory.path);
209     if (configuration._cacheStorageDirectory)
210         config->setCacheStorageDirectory(configuration._cacheStorageDirectory.path);
211     if (configuration._serviceWorkerRegistrationDirectory)
212         config->setServiceWorkerRegistrationDirectory(configuration._serviceWorkerRegistrationDirectory.path);
213     if (configuration.sourceApplicationBundleIdentifier)
214         config->setSourceApplicationBundleIdentifier(configuration.sourceApplicationBundleIdentifier);
215     if (configuration.sourceApplicationSecondaryIdentifier)
216         config->setSourceApplicationSecondaryIdentifier(configuration.sourceApplicationSecondaryIdentifier);
217
218     API::Object::constructInWrapper<API::WebsiteDataStore>(self, WTFMove(config), PAL::SessionID::generatePersistentSessionID());
219
220     return self;
221 }
222
223 - (void)_fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes withOptions:(_WKWebsiteDataStoreFetchOptions)options completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
224 {
225     auto completionHandlerCopy = makeBlockPtr(completionHandler);
226
227     OptionSet<WebKit::WebsiteDataFetchOption> fetchOptions;
228     if (options & _WKWebsiteDataStoreFetchOptionComputeSizes)
229         fetchOptions.add(WebKit::WebsiteDataFetchOption::ComputeSizes);
230
231     _websiteDataStore->websiteDataStore().fetchData(WebKit::toWebsiteDataTypes(dataTypes), fetchOptions, [completionHandlerCopy = WTFMove(completionHandlerCopy)](auto websiteDataRecords) {
232         Vector<RefPtr<API::Object>> elements;
233         elements.reserveInitialCapacity(websiteDataRecords.size());
234
235         for (auto& websiteDataRecord : websiteDataRecords)
236             elements.uncheckedAppend(API::WebsiteDataRecord::create(WTFMove(websiteDataRecord)));
237
238         completionHandlerCopy(wrapper(API::Array::create(WTFMove(elements))));
239     });
240 }
241
242 - (BOOL)_resourceLoadStatisticsEnabled
243 {
244     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsEnabled();
245 }
246
247 - (void)_setResourceLoadStatisticsEnabled:(BOOL)enabled
248 {
249     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsEnabled(enabled);
250 }
251
252 - (BOOL)_resourceLoadStatisticsDebugMode
253 {
254     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsDebugMode();
255 }
256
257 - (void)_setResourceLoadStatisticsDebugMode:(BOOL)enabled
258 {
259     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsDebugMode(enabled);
260 }
261
262 - (NSUInteger)_cacheStoragePerOriginQuota
263 {
264     return _websiteDataStore->websiteDataStore().cacheStoragePerOriginQuota();
265 }
266
267 - (void)_setCacheStoragePerOriginQuota:(NSUInteger)size
268 {
269     _websiteDataStore->websiteDataStore().setCacheStoragePerOriginQuota(size);
270 }
271
272 - (NSString *)_cacheStorageDirectory
273 {
274     return _websiteDataStore->websiteDataStore().cacheStorageDirectory();
275 }
276
277 - (void)_setCacheStorageDirectory:(NSString *)directory
278 {
279     _websiteDataStore->websiteDataStore().setCacheStorageDirectory(directory);
280 }
281
282 - (NSString *)_serviceWorkerRegistrationDirectory
283 {
284     return _websiteDataStore->websiteDataStore().serviceWorkerRegistrationDirectory();
285 }
286
287 - (void)_setServiceWorkerRegistrationDirectory:(NSString *)directory
288 {
289     _websiteDataStore->websiteDataStore().setServiceWorkerRegistrationDirectory(directory);
290 }
291
292 - (void)_setBoundInterfaceIdentifier:(NSString *)identifier
293 {
294     _websiteDataStore->websiteDataStore().setBoundInterfaceIdentifier(identifier);
295 }
296
297 - (NSString *)_boundInterfaceIdentifier
298 {
299     return _websiteDataStore->websiteDataStore().boundInterfaceIdentifier();
300 }
301
302 - (void)_setAllowsCellularAccess:(BOOL)allows
303 {
304     _websiteDataStore->websiteDataStore().setAllowsCellularAccess(allows ? WebKit::AllowsCellularAccess::Yes : WebKit::AllowsCellularAccess::No);
305 }
306
307 - (BOOL)_allowsCellularAccess
308 {
309     return _websiteDataStore->websiteDataStore().allowsCellularAccess() == WebKit::AllowsCellularAccess::Yes;
310 }
311
312 - (void)_setProxyConfiguration:(NSDictionary *)configuration
313 {
314     _websiteDataStore->websiteDataStore().setProxyConfiguration((__bridge CFDictionaryRef)configuration);
315 }
316
317 - (NSDictionary *)_proxyConfiguration
318 {
319     return (__bridge NSDictionary *)_websiteDataStore->websiteDataStore().proxyConfiguration();
320 }
321
322 - (void)_resourceLoadStatisticsSetShouldSubmitTelemetry:(BOOL)value
323 {
324     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
325     if (!store)
326         return;
327
328     store->setShouldSubmitTelemetry(value);
329 }
330
331 - (void)_setResourceLoadStatisticsTestingCallback:(void (^)(WKWebsiteDataStore *, NSString *))callback
332 {
333     if (!_websiteDataStore->isPersistent())
334         return;
335
336     if (callback) {
337         _websiteDataStore->websiteDataStore().enableResourceLoadStatisticsAndSetTestingCallback([callback = makeBlockPtr(callback), self](const String& event) {
338             callback(self, (NSString *)event);
339         });
340         return;
341     }
342
343     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
344     if (!store)
345         return;
346
347     store->setStatisticsTestingCallback(nullptr);
348 }
349
350 + (void)_allowWebsiteDataRecordsForAllOrigins
351 {
352     WebKit::WebsiteDataStore::allowWebsiteDataRecordsForAllOrigins();
353 }
354
355 - (void)_getAllStorageAccessEntriesFor:(WKWebView *)webView completionHandler:(void (^)(NSArray<NSString *> *domains))completionHandler
356 {
357     if (!webView) {
358         completionHandler({ });
359         return;
360     }
361
362     auto* webPageProxy = [webView _page];
363     if (!webPageProxy) {
364         completionHandler({ });
365         return;
366     }
367
368     _websiteDataStore->websiteDataStore().getAllStorageAccessEntries(webPageProxy->pageID(), [completionHandler = makeBlockPtr(completionHandler)](auto domains) {
369         Vector<RefPtr<API::Object>> apiDomains;
370         apiDomains.reserveInitialCapacity(domains.size());
371         for (auto& domain : domains)
372             apiDomains.uncheckedAppend(API::String::create(domain));
373         completionHandler(wrapper(API::Array::create(WTFMove(apiDomains))));
374     });
375 }
376
377 - (bool)_hasRegisteredServiceWorker
378 {
379     return WebKit::ServiceWorkerProcessProxy::hasRegisteredServiceWorkers(_websiteDataStore->websiteDataStore().serviceWorkerRegistrationDirectory());
380 }
381
382 @end
383
384 #endif // WK_API_ENABLED