Unreviewed, fix iOS build with recent SDKs.
[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 #import "APIString.h"
30 #import "CompletionHandlerCallChecker.h"
31 #import "WKHTTPCookieStoreInternal.h"
32 #import "WKNSArray.h"
33 #import "WKWebViewInternal.h"
34 #import "WKWebsiteDataRecordInternal.h"
35 #import "WebPageProxy.h"
36 #import "WebResourceLoadStatisticsStore.h"
37 #import "WebResourceLoadStatisticsTelemetry.h"
38 #import "WebsiteDataFetchOption.h"
39 #import "_WKWebsiteDataStoreConfiguration.h"
40 #import "_WKWebsiteDataStoreDelegate.h"
41 #import <WebKit/ServiceWorkerProcessProxy.h>
42 #import <wtf/BlockPtr.h>
43 #import <wtf/URL.h>
44 #import <wtf/WeakObjCPtr.h>
45
46 class WebsiteDataStoreClient : public WebKit::WebsiteDataStoreClient {
47 public:
48     explicit WebsiteDataStoreClient(id <_WKWebsiteDataStoreDelegate> delegate)
49         : m_delegate(delegate)
50         , m_hasRequestStorageSpaceSelector([m_delegate.get() respondsToSelector:@selector(requestStorageSpace: frameOrigin: quota: currentSize: spaceRequired: decisionHandler:)])
51     {
52     }
53
54 private:
55     void requestStorageSpace(const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& frameOrigin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(Optional<uint64_t>)>&& completionHandler) final
56     {
57         if (!m_hasRequestStorageSpaceSelector || !m_delegate) {
58             completionHandler({ });
59             return;
60         }
61
62         auto checker = WebKit::CompletionHandlerCallChecker::create(m_delegate.getAutoreleased(), @selector(requestStorageSpace: frameOrigin: quota: currentSize: spaceRequired: decisionHandler:));
63         auto decisionHandler = makeBlockPtr([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long quota) mutable {
64             if (checker->completionHandlerHasBeenCalled())
65                 return;
66             checker->didCallCompletionHandler();
67             completionHandler(quota);
68         });
69
70         URL mainFrameURL { URL(), topOrigin.toString() };
71         URL frameURL { URL(), frameOrigin.toString() };
72
73         [m_delegate.getAutoreleased() requestStorageSpace:mainFrameURL frameOrigin:frameURL quota:quota currentSize:currentSize spaceRequired:spaceRequired decisionHandler:decisionHandler.get()];
74     }
75
76     WeakObjCPtr<id <_WKWebsiteDataStoreDelegate> > m_delegate;
77     bool m_hasRequestStorageSpaceSelector { false };
78 };
79
80 @implementation WKWebsiteDataStore
81
82 + (WKWebsiteDataStore *)defaultDataStore
83 {
84     return wrapper(API::WebsiteDataStore::defaultDataStore());
85 }
86
87 + (WKWebsiteDataStore *)nonPersistentDataStore
88 {
89     return wrapper(API::WebsiteDataStore::createNonPersistentDataStore());
90 }
91
92 - (void)dealloc
93 {
94     _websiteDataStore->API::WebsiteDataStore::~WebsiteDataStore();
95
96     [super dealloc];
97 }
98
99 + (BOOL)supportsSecureCoding
100 {
101     return YES;
102 }
103
104 - (instancetype)initWithCoder:(NSCoder *)coder
105 {
106     if (!(self = [super init]))
107         return nil;
108
109     RetainPtr<WKWebsiteDataStore> dataStore;
110     if ([coder decodeBoolForKey:@"isDefaultDataStore"])
111         dataStore = [WKWebsiteDataStore defaultDataStore];
112     else
113         dataStore = [WKWebsiteDataStore nonPersistentDataStore];
114
115     [self release];
116
117     return dataStore.leakRef();
118 }
119
120 - (void)encodeWithCoder:(NSCoder *)coder
121 {
122     if (self == [WKWebsiteDataStore defaultDataStore]) {
123         [coder encodeBool:YES forKey:@"isDefaultDataStore"];
124         return;
125     }
126
127     ASSERT(!self.persistent);
128 }
129
130 - (BOOL)isPersistent
131 {
132     return _websiteDataStore->isPersistent();
133 }
134
135 + (NSSet *)allWebsiteDataTypes
136 {
137     static dispatch_once_t onceToken;
138     static NSSet *allWebsiteDataTypes;
139     dispatch_once(&onceToken, ^{
140         allWebsiteDataTypes = [[NSSet alloc] initWithArray:@[ WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeFetchCache, WKWebsiteDataTypeMemoryCache, WKWebsiteDataTypeOfflineWebApplicationCache, WKWebsiteDataTypeCookies, WKWebsiteDataTypeSessionStorage, WKWebsiteDataTypeLocalStorage, WKWebsiteDataTypeIndexedDBDatabases, WKWebsiteDataTypeServiceWorkerRegistrations, WKWebsiteDataTypeWebSQLDatabases ]];
141     });
142
143     return allWebsiteDataTypes;
144 }
145
146 - (WKHTTPCookieStore *)httpCookieStore
147 {
148     return wrapper(_websiteDataStore->httpCookieStore());
149 }
150
151 static WallTime toSystemClockTime(NSDate *date)
152 {
153     ASSERT(date);
154     return WallTime::fromRawSeconds(date.timeIntervalSince1970);
155 }
156
157 - (void)fetchDataRecordsOfTypes:(NSSet *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
158 {
159     [self _fetchDataRecordsOfTypes:dataTypes withOptions:0 completionHandler:completionHandler];
160 }
161
162 - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler
163 {
164     auto completionHandlerCopy = makeBlockPtr(completionHandler);
165     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toSystemClockTime(date ? date : [NSDate distantPast]), [completionHandlerCopy] {
166         completionHandlerCopy();
167     });
168 }
169
170 static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecords)
171 {
172     Vector<WebKit::WebsiteDataRecord> result;
173
174     for (WKWebsiteDataRecord *dataRecord in dataRecords)
175         result.append(dataRecord->_websiteDataRecord->websiteDataRecord());
176
177     return result;
178 }
179
180 - (void)removeDataOfTypes:(NSSet *)dataTypes forDataRecords:(NSArray *)dataRecords completionHandler:(void (^)(void))completionHandler
181 {
182     auto completionHandlerCopy = makeBlockPtr(completionHandler);
183
184     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toWebsiteDataRecords(dataRecords), [completionHandlerCopy] {
185         completionHandlerCopy();
186     });
187 }
188
189 #pragma mark WKObject protocol implementation
190
191 - (API::Object&)_apiObject
192 {
193     return *_websiteDataStore;
194 }
195
196 @end
197
198 @implementation WKWebsiteDataStore (WKPrivate)
199
200 + (NSSet<NSString *> *)_allWebsiteDataTypesIncludingPrivate
201 {
202     static dispatch_once_t onceToken;
203     static NSSet *allWebsiteDataTypes;
204     dispatch_once(&onceToken, ^ {
205         auto *privateTypes = @[_WKWebsiteDataTypeHSTSCache, _WKWebsiteDataTypeMediaKeys, _WKWebsiteDataTypeSearchFieldRecentSearches, _WKWebsiteDataTypeResourceLoadStatistics, _WKWebsiteDataTypeCredentials
206 #if !TARGET_OS_IPHONE
207         , _WKWebsiteDataTypePlugInData
208 #endif
209         ];
210
211         allWebsiteDataTypes = [[[self allWebsiteDataTypes] setByAddingObjectsFromArray:privateTypes] retain];
212     });
213
214     return allWebsiteDataTypes;
215 }
216
217 + (BOOL)_defaultDataStoreExists
218 {
219     return API::WebsiteDataStore::defaultDataStoreExists();
220 }
221
222 + (void)_deleteDefaultDataStoreForTesting
223 {
224     return API::WebsiteDataStore::deleteDefaultDataStoreForTesting();
225 }
226
227 - (instancetype)_initWithConfiguration:(_WKWebsiteDataStoreConfiguration *)configuration
228 {
229     if (!(self = [super init]))
230         return nil;
231
232     auto config = API::WebsiteDataStore::defaultDataStoreConfiguration();
233
234     if (configuration._webStorageDirectory)
235         config->setLocalStorageDirectory(configuration._webStorageDirectory.path);
236     if (configuration._webSQLDatabaseDirectory)
237         config->setWebSQLDatabaseDirectory(configuration._webSQLDatabaseDirectory.path);
238     if (configuration._indexedDBDatabaseDirectory)
239         config->setIndexedDBDatabaseDirectory(configuration._indexedDBDatabaseDirectory.path);
240     if (configuration._cookieStorageFile)
241         config->setCookieStorageFile(configuration._cookieStorageFile.path);
242     if (configuration._resourceLoadStatisticsDirectory)
243         config->setResourceLoadStatisticsDirectory(configuration._resourceLoadStatisticsDirectory.path);
244     if (configuration._cacheStorageDirectory)
245         config->setCacheStorageDirectory(configuration._cacheStorageDirectory.path);
246     if (configuration._serviceWorkerRegistrationDirectory)
247         config->setServiceWorkerRegistrationDirectory(configuration._serviceWorkerRegistrationDirectory.path);
248     if (configuration.sourceApplicationBundleIdentifier)
249         config->setSourceApplicationBundleIdentifier(configuration.sourceApplicationBundleIdentifier);
250     if (configuration.sourceApplicationSecondaryIdentifier)
251         config->setSourceApplicationSecondaryIdentifier(configuration.sourceApplicationSecondaryIdentifier);
252     if (configuration.httpProxy)
253         config->setHTTPProxy(configuration.httpProxy);
254     if (configuration.httpsProxy)
255         config->setHTTPSProxy(configuration.httpsProxy);
256
257     API::Object::constructInWrapper<API::WebsiteDataStore>(self, WTFMove(config), PAL::SessionID::generatePersistentSessionID());
258
259     return self;
260 }
261
262 - (void)_fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes withOptions:(_WKWebsiteDataStoreFetchOptions)options completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
263 {
264     auto completionHandlerCopy = makeBlockPtr(completionHandler);
265
266     OptionSet<WebKit::WebsiteDataFetchOption> fetchOptions;
267     if (options & _WKWebsiteDataStoreFetchOptionComputeSizes)
268         fetchOptions.add(WebKit::WebsiteDataFetchOption::ComputeSizes);
269
270     _websiteDataStore->websiteDataStore().fetchData(WebKit::toWebsiteDataTypes(dataTypes), fetchOptions, [completionHandlerCopy = WTFMove(completionHandlerCopy)](auto websiteDataRecords) {
271         Vector<RefPtr<API::Object>> elements;
272         elements.reserveInitialCapacity(websiteDataRecords.size());
273
274         for (auto& websiteDataRecord : websiteDataRecords)
275             elements.uncheckedAppend(API::WebsiteDataRecord::create(WTFMove(websiteDataRecord)));
276
277         completionHandlerCopy(wrapper(API::Array::create(WTFMove(elements))));
278     });
279 }
280
281 - (BOOL)_resourceLoadStatisticsEnabled
282 {
283     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsEnabled();
284 }
285
286 - (void)_setResourceLoadStatisticsEnabled:(BOOL)enabled
287 {
288     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsEnabled(enabled);
289 }
290
291 - (BOOL)_resourceLoadStatisticsDebugMode
292 {
293 #if ENABLE(RESOURCE_LOAD_STATISTICS)
294     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsDebugMode();
295 #else
296     return NO;
297 #endif
298 }
299
300 - (void)_setResourceLoadStatisticsDebugMode:(BOOL)enabled
301 {
302 #if ENABLE(RESOURCE_LOAD_STATISTICS)
303     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsDebugMode(enabled);
304 #else
305     UNUSED_PARAM(enabled);
306 #endif
307 }
308
309 - (NSUInteger)_perOriginStorageQuota
310 {
311     return _websiteDataStore->websiteDataStore().perOriginStorageQuota();
312 }
313
314 - (void)_setPerOriginStorageQuota:(NSUInteger)size
315 {
316     _websiteDataStore->websiteDataStore().setPerOriginStorageQuota(size);
317 }
318
319 - (NSString *)_cacheStorageDirectory
320 {
321     return _websiteDataStore->websiteDataStore().cacheStorageDirectory();
322 }
323
324 - (void)_setCacheStorageDirectory:(NSString *)directory
325 {
326     _websiteDataStore->websiteDataStore().setCacheStorageDirectory(directory);
327 }
328
329 - (NSString *)_serviceWorkerRegistrationDirectory
330 {
331     return _websiteDataStore->websiteDataStore().serviceWorkerRegistrationDirectory();
332 }
333
334 - (void)_setServiceWorkerRegistrationDirectory:(NSString *)directory
335 {
336     _websiteDataStore->websiteDataStore().setServiceWorkerRegistrationDirectory(directory);
337 }
338
339 - (void)_setBoundInterfaceIdentifier:(NSString *)identifier
340 {
341     _websiteDataStore->websiteDataStore().setBoundInterfaceIdentifier(identifier);
342 }
343
344 - (NSString *)_boundInterfaceIdentifier
345 {
346     return _websiteDataStore->websiteDataStore().boundInterfaceIdentifier();
347 }
348
349 - (void)_setAllowsCellularAccess:(BOOL)allows
350 {
351     _websiteDataStore->websiteDataStore().setAllowsCellularAccess(allows ? WebKit::AllowsCellularAccess::Yes : WebKit::AllowsCellularAccess::No);
352 }
353
354 - (BOOL)_allowsCellularAccess
355 {
356     return _websiteDataStore->websiteDataStore().allowsCellularAccess() == WebKit::AllowsCellularAccess::Yes;
357 }
358
359 - (void)_setProxyConfiguration:(NSDictionary *)configuration
360 {
361     _websiteDataStore->websiteDataStore().setProxyConfiguration((__bridge CFDictionaryRef)configuration);
362 }
363
364 - (NSString *)_sourceApplicationBundleIdentifier
365 {
366     return _websiteDataStore->websiteDataStore().sourceApplicationBundleIdentifier();
367 }
368
369 - (void)_setSourceApplicationBundleIdentifier:(NSString *)identifier
370 {
371     if (!_websiteDataStore->websiteDataStore().setSourceApplicationBundleIdentifier(identifier))
372         [NSException raise:NSGenericException format:@"_setSourceApplicationBundleIdentifier cannot be called after networking has begun"];
373 }
374
375 - (NSString *)_sourceApplicationSecondaryIdentifier
376 {
377     return _websiteDataStore->websiteDataStore().sourceApplicationSecondaryIdentifier();
378 }
379
380 - (void)_setSourceApplicationSecondaryIdentifier:(NSString *)identifier
381 {
382     if (!_websiteDataStore->websiteDataStore().setSourceApplicationSecondaryIdentifier(identifier))
383         [NSException raise:NSGenericException format:@"_setSourceApplicationSecondaryIdentifier cannot be called after networking has begun"];
384 }
385
386 - (void)_setAllowsTLSFallback:(BOOL)allows
387 {
388     if (!_websiteDataStore->websiteDataStore().setAllowsTLSFallback(allows))
389         [NSException raise:NSGenericException format:@"_setAllowsTLSFallback cannot be called after networking has begun"];
390 }
391
392 - (BOOL)_allowsTLSFallback
393 {
394     return _websiteDataStore->websiteDataStore().allowsTLSFallback();
395 }
396
397 - (NSDictionary *)_proxyConfiguration
398 {
399     return (__bridge NSDictionary *)_websiteDataStore->websiteDataStore().proxyConfiguration();
400 }
401
402 - (NSURL *)_indexedDBDatabaseDirectory
403 {
404     return [NSURL fileURLWithPath:_websiteDataStore->indexedDBDatabaseDirectory() isDirectory:YES];
405 }
406
407 - (void)_resourceLoadStatisticsSetShouldSubmitTelemetry:(BOOL)value
408 {
409 #if ENABLE(RESOURCE_LOAD_STATISTICS)
410     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
411     if (!store)
412         return;
413
414     store->setShouldSubmitTelemetry(value);
415 #endif
416 }
417
418 - (void)_setResourceLoadStatisticsTestingCallback:(void (^)(WKWebsiteDataStore *, NSString *))callback
419 {
420 #if ENABLE(RESOURCE_LOAD_STATISTICS)
421     if (!_websiteDataStore->isPersistent())
422         return;
423
424     if (callback) {
425         _websiteDataStore->websiteDataStore().enableResourceLoadStatisticsAndSetTestingCallback([callback = makeBlockPtr(callback), self](const String& event) {
426             callback(self, (NSString *)event);
427         });
428         return;
429     }
430
431     _websiteDataStore->websiteDataStore().setStatisticsTestingCallback(nullptr);
432 #endif
433 }
434
435 + (void)_allowWebsiteDataRecordsForAllOrigins
436 {
437     WebKit::WebsiteDataStore::allowWebsiteDataRecordsForAllOrigins();
438 }
439
440 - (void)_getAllStorageAccessEntriesFor:(WKWebView *)webView completionHandler:(void (^)(NSArray<NSString *> *domains))completionHandler
441 {
442     if (!webView) {
443         completionHandler({ });
444         return;
445     }
446
447     auto* webPageProxy = [webView _page];
448     if (!webPageProxy) {
449         completionHandler({ });
450         return;
451     }
452
453 #if ENABLE(RESOURCE_LOAD_STATISTICS)
454     _websiteDataStore->websiteDataStore().getAllStorageAccessEntries(webPageProxy->pageID(), [completionHandler = makeBlockPtr(completionHandler)](auto domains) {
455         Vector<RefPtr<API::Object>> apiDomains;
456         apiDomains.reserveInitialCapacity(domains.size());
457         for (auto& domain : domains)
458             apiDomains.uncheckedAppend(API::String::create(domain));
459         completionHandler(wrapper(API::Array::create(WTFMove(apiDomains))));
460     });
461 #else
462     completionHandler({ });
463 #endif
464 }
465
466 - (bool)_hasRegisteredServiceWorker
467 {
468     return WebKit::ServiceWorkerProcessProxy::hasRegisteredServiceWorkers(_websiteDataStore->websiteDataStore().serviceWorkerRegistrationDirectory());
469 }
470
471 - (id <_WKWebsiteDataStoreDelegate>)_delegate
472 {
473     return _delegate.get();
474 }
475
476 - (void)set_delegate:(id <_WKWebsiteDataStoreDelegate>)delegate
477 {
478     _delegate = delegate;
479     _websiteDataStore->websiteDataStore().setClient(makeUniqueRef<WebsiteDataStoreClient>(delegate));
480 }
481
482 @end