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