b8c9002531e6bce43117561b2d113da9bed47244
[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 "WKHTTPCookieStoreInternal.h"
32 #import "WKNSArray.h"
33 #import "WKWebsiteDataRecordInternal.h"
34 #import "WebResourceLoadStatisticsStore.h"
35 #import "WebResourceLoadStatisticsTelemetry.h"
36 #import "WebsiteDataFetchOption.h"
37 #import "_WKWebsiteDataStoreConfiguration.h"
38 #import <WebCore/URL.h>
39 #import <wtf/BlockPtr.h>
40
41 using namespace WebCore;
42
43 @implementation WKWebsiteDataStore
44
45 + (WKWebsiteDataStore *)defaultDataStore
46 {
47     return WebKit::wrapper(API::WebsiteDataStore::defaultDataStore().get());
48 }
49
50 + (WKWebsiteDataStore *)nonPersistentDataStore
51 {
52     return [WebKit::wrapper(API::WebsiteDataStore::createNonPersistentDataStore().leakRef()) autorelease];
53 }
54
55 - (void)dealloc
56 {
57     _websiteDataStore->API::WebsiteDataStore::~WebsiteDataStore();
58
59     [super dealloc];
60 }
61
62 - (instancetype)initWithCoder:(NSCoder *)coder
63 {
64     if (!(self = [super init]))
65         return nil;
66
67     RetainPtr<WKWebsiteDataStore> dataStore;
68     if ([coder decodeBoolForKey:@"isDefaultDataStore"])
69         dataStore = [WKWebsiteDataStore defaultDataStore];
70     else
71         dataStore = [WKWebsiteDataStore nonPersistentDataStore];
72
73     [self release];
74
75     return dataStore.leakRef();
76 }
77
78 - (void)encodeWithCoder:(NSCoder *)coder
79 {
80     if (self == [WKWebsiteDataStore defaultDataStore]) {
81         [coder encodeBool:YES forKey:@"isDefaultDataStore"];
82         return;
83     }
84
85     ASSERT(!self.persistent);
86 }
87
88 - (BOOL)isPersistent
89 {
90     return _websiteDataStore->isPersistent();
91 }
92
93 + (NSSet *)allWebsiteDataTypes
94 {
95     static dispatch_once_t onceToken;
96     static NSSet *allWebsiteDataTypes;
97     dispatch_once(&onceToken, ^{
98         allWebsiteDataTypes = [[NSSet alloc] initWithArray:@[ WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache, WKWebsiteDataTypeOfflineWebApplicationCache, WKWebsiteDataTypeCookies, WKWebsiteDataTypeSessionStorage, WKWebsiteDataTypeLocalStorage, WKWebsiteDataTypeIndexedDBDatabases, WKWebsiteDataTypeWebSQLDatabases ]];
99     });
100
101     return allWebsiteDataTypes;
102 }
103
104 - (WKHTTPCookieStore *)httpCookieStore
105 {
106     return WebKit::wrapper(_websiteDataStore->httpCookieStore());
107 }
108
109 static std::chrono::system_clock::time_point toSystemClockTime(NSDate *date)
110 {
111     ASSERT(date);
112     using namespace std::chrono;
113
114     return system_clock::time_point(duration_cast<system_clock::duration>(duration<double>(date.timeIntervalSince1970)));
115 }
116
117 - (void)fetchDataRecordsOfTypes:(NSSet *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
118 {
119     [self _fetchDataRecordsOfTypes:dataTypes withOptions:0 completionHandler:completionHandler];
120 }
121
122 - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler
123 {
124     auto completionHandlerCopy = makeBlockPtr(completionHandler);
125     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toSystemClockTime(date ? date : [NSDate distantPast]), [completionHandlerCopy] {
126         completionHandlerCopy();
127     });
128 }
129
130 static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecords)
131 {
132     Vector<WebKit::WebsiteDataRecord> result;
133
134     for (WKWebsiteDataRecord *dataRecord in dataRecords)
135         result.append(dataRecord->_websiteDataRecord->websiteDataRecord());
136
137     return result;
138 }
139
140 - (void)removeDataOfTypes:(NSSet *)dataTypes forDataRecords:(NSArray *)dataRecords completionHandler:(void (^)(void))completionHandler
141 {
142     auto completionHandlerCopy = makeBlockPtr(completionHandler);
143
144     _websiteDataStore->websiteDataStore().removeData(WebKit::toWebsiteDataTypes(dataTypes), toWebsiteDataRecords(dataRecords), [completionHandlerCopy] {
145         completionHandlerCopy();
146     });
147 }
148
149 #pragma mark WKObject protocol implementation
150
151 - (API::Object&)_apiObject
152 {
153     return *_websiteDataStore;
154 }
155
156 @end
157
158 @implementation WKWebsiteDataStore (WKPrivate)
159
160 + (NSSet<NSString *> *)_allWebsiteDataTypesIncludingPrivate
161 {
162     static dispatch_once_t onceToken;
163     static NSSet *allWebsiteDataTypes;
164     dispatch_once(&onceToken, ^ {
165         auto *privateTypes = @[_WKWebsiteDataTypeHSTSCache, _WKWebsiteDataTypeMediaKeys, _WKWebsiteDataTypeSearchFieldRecentSearches, _WKWebsiteDataTypeResourceLoadStatistics, _WKWebsiteDataTypeCredentials
166 #if !TARGET_OS_IPHONE
167         , _WKWebsiteDataTypePlugInData
168 #endif
169         ];
170
171         allWebsiteDataTypes = [[[self allWebsiteDataTypes] setByAddingObjectsFromArray:privateTypes] retain];
172     });
173
174     return allWebsiteDataTypes;
175 }
176
177 - (instancetype)_initWithConfiguration:(_WKWebsiteDataStoreConfiguration *)configuration
178 {
179     if (!(self = [super init]))
180         return nil;
181
182     auto config = API::WebsiteDataStore::defaultDataStoreConfiguration();
183
184     if (configuration._webStorageDirectory)
185         config.localStorageDirectory = configuration._webStorageDirectory.path;
186     if (configuration._webSQLDatabaseDirectory)
187         config.webSQLDatabaseDirectory = configuration._webSQLDatabaseDirectory.path;
188     if (configuration._indexedDBDatabaseDirectory)
189         config.indexedDBDatabaseDirectory = configuration._indexedDBDatabaseDirectory.path;
190     if (configuration._cookieStorageFile)
191         config.cookieStorageFile = configuration._cookieStorageFile.path;
192     if (configuration._resourceLoadStatisticsDirectory)
193         config.resourceLoadStatisticsDirectory = configuration._resourceLoadStatisticsDirectory.path;
194
195     API::Object::constructInWrapper<API::WebsiteDataStore>(self, config, PAL::SessionID::generatePersistentSessionID());
196
197     return self;
198 }
199
200 - (void)_fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes withOptions:(_WKWebsiteDataStoreFetchOptions)options completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler
201 {
202     auto completionHandlerCopy = makeBlockPtr(completionHandler);
203
204     OptionSet<WebKit::WebsiteDataFetchOption> fetchOptions;
205     if (options & _WKWebsiteDataStoreFetchOptionComputeSizes)
206         fetchOptions |= WebKit::WebsiteDataFetchOption::ComputeSizes;
207
208     _websiteDataStore->websiteDataStore().fetchData(WebKit::toWebsiteDataTypes(dataTypes), fetchOptions, [completionHandlerCopy = WTFMove(completionHandlerCopy)](auto websiteDataRecords) {
209         Vector<RefPtr<API::Object>> elements;
210         elements.reserveInitialCapacity(websiteDataRecords.size());
211
212         for (auto& websiteDataRecord : websiteDataRecords)
213             elements.uncheckedAppend(API::WebsiteDataRecord::create(WTFMove(websiteDataRecord)));
214
215         completionHandlerCopy(wrapper(API::Array::create(WTFMove(elements))));
216     });
217 }
218
219 - (BOOL)_resourceLoadStatisticsEnabled
220 {
221     return _websiteDataStore->websiteDataStore().resourceLoadStatisticsEnabled();
222 }
223
224 - (void)_setResourceLoadStatisticsEnabled:(BOOL)enabled
225 {
226     _websiteDataStore->websiteDataStore().setResourceLoadStatisticsEnabled(enabled);
227 }
228
229 - (void)_resourceLoadStatisticsSetLastSeen:(double)seconds forHost:(NSString *)host
230 {
231     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
232     if (!store)
233         return;
234     
235     store->setLastSeen(URL(URL(), host), Seconds { seconds });
236 }
237
238 - (void)_resourceLoadStatisticsSetIsPrevalentResource:(BOOL)value forHost:(NSString *)host
239 {
240     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
241     if (!store)
242         return;
243
244     if (value)
245         store->setPrevalentResource(URL(URL(), host));
246     else
247         store->clearPrevalentResource(URL(URL(), host));
248 }
249
250 - (void)_resourceLoadStatisticsIsPrevalentResource:(NSString *)host completionHandler:(void (^)(BOOL))completionHandler
251 {
252     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
253     if (!store) {
254         completionHandler(NO);
255         return;
256     }
257
258     auto completionHandlerCopy = makeBlockPtr(completionHandler);
259     store->isPrevalentResource(URL(URL(), host), [completionHandlerCopy](bool isPrevalentResource) {
260         completionHandlerCopy(isPrevalentResource);
261     });
262 }
263
264 - (void)_resourceLoadStatisticsSetHadUserInteraction:(BOOL)value forHost:(NSString *)host
265 {
266     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
267     if (!store)
268         return;
269
270     if (value)
271         store->logUserInteraction(URL(URL(), host));
272     else
273         store->clearUserInteraction(URL(URL(), host));
274 }
275
276 - (void)_resourceLoadStatisticsHadUserInteraction:(NSString *)host completionHandler:(void (^)(BOOL))completionHandler
277 {
278     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
279     if (!store) {
280         completionHandler(NO);
281         return;
282     }
283
284     auto completionHandlerCopy = makeBlockPtr(completionHandler);
285     store->hasHadUserInteraction(URL(URL(), host), [completionHandlerCopy](bool hasHadUserInteraction) {
286         completionHandlerCopy(hasHadUserInteraction);
287     });
288 }
289
290 - (void)_resourceLoadStatisticsSetIsGrandfathered:(BOOL)value forHost:(NSString *)host
291 {
292     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
293     if (!store)
294         return;
295
296     store->setGrandfathered(URL(URL(), host), value);
297 }
298
299 - (void)_resourceLoadStatisticsIsGrandfathered:(NSString *)host completionHandler:(void (^)(BOOL))completionHandler
300 {
301     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
302     if (!store) {
303         completionHandler(NO);
304         return;
305     }
306
307     auto completionHandlerCopy = makeBlockPtr(completionHandler);
308     store->isGrandfathered(URL(URL(), host), [completionHandlerCopy](bool isGrandfathered) {
309         completionHandlerCopy(isGrandfathered);
310     });
311 }
312
313 - (void)_resourceLoadStatisticsSetSubframeUnderTopFrameOrigin:(NSString *)topFrameHostName forHost:(NSString *)host
314 {
315     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
316     if (!store)
317         return;
318
319     store->setSubframeUnderTopFrameOrigin(URL(URL(), host), URL(URL(), topFrameHostName));
320 }
321
322 - (void)_resourceLoadStatisticsSetSubresourceUnderTopFrameOrigin:(NSString *)topFrameHostName forHost:(NSString *)host
323 {
324     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
325     if (!store)
326         return;
327
328     store->setSubresourceUnderTopFrameOrigin(URL(URL(), host), URL(URL(), topFrameHostName));
329 }
330
331 - (void)_resourceLoadStatisticsSetSubresourceUniqueRedirectTo:(NSString *)hostNameRedirectedTo forHost:(NSString *)host
332 {
333     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
334     if (!store)
335         return;
336
337     store->setSubresourceUniqueRedirectTo(URL(URL(), host), URL(URL(), hostNameRedirectedTo));
338 }
339
340 - (void)_resourceLoadStatisticsSetTimeToLiveUserInteraction:(double)seconds
341 {
342     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
343     if (!store)
344         return;
345
346     store->setTimeToLiveUserInteraction(Seconds { seconds });
347 }
348
349 - (void)_resourceLoadStatisticsSetTimeToLiveCookiePartitionFree:(double)seconds
350 {
351     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
352     if (!store)
353         return;
354
355     store->setTimeToLiveCookiePartitionFree(Seconds { seconds });
356 }
357
358 - (void)_resourceLoadStatisticsSetMinimumTimeBetweenDataRecordsRemoval:(double)seconds
359 {
360     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
361     if (!store)
362         return;
363
364     store->setMinimumTimeBetweenDataRecordsRemoval(Seconds { seconds });
365 }
366
367 - (void)_resourceLoadStatisticsSetGrandfatheringTime:(double)seconds
368 {
369     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
370     if (!store)
371         return;
372
373     store->setGrandfatheringTime(Seconds {seconds });
374 }
375
376 - (void)_resourceLoadStatisticsSetMaxStatisticsEntries:(size_t)entries
377 {
378     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
379     if (!store)
380         return;
381
382     store->setMaxStatisticsEntries(entries);
383 }
384
385 - (void)_resourceLoadStatisticsSetPruneEntriesDownTo:(size_t)entries
386 {
387     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
388     if (!store)
389         return;
390
391     store->setPruneEntriesDownTo(entries);
392 }
393
394 - (void)_resourceLoadStatisticsProcessStatisticsAndDataRecords
395 {
396     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
397     if (!store)
398         return;
399
400     store->scheduleStatisticsAndDataRecordsProcessing();
401 }
402
403 - (void)_resourceLoadStatisticsUpdateCookiePartitioning
404 {
405     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
406     if (!store)
407         return;
408
409     store->scheduleCookiePartitioningUpdate();
410 }
411
412 - (void)_resourceLoadStatisticsSetShouldPartitionCookies:(BOOL)value forHost:(NSString *)host
413 {
414     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
415     if (!store)
416         return;
417
418     if (value)
419         store->scheduleCookiePartitioningUpdateForDomains({ }, { host }, WebKit::ShouldClearFirst::No);
420     else
421         store->scheduleClearPartitioningStateForDomains({ host });
422 }
423
424 - (void)_resourceLoadStatisticsSubmitTelemetry
425 {
426     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
427     if (!store)
428         return;
429
430     store->submitTelemetry();
431 }
432
433 - (void)_resourceLoadStatisticsSetNotifyPagesWhenDataRecordsWereScanned:(BOOL)value
434 {
435     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
436     if (!store)
437         return;
438
439     store->setNotifyPagesWhenDataRecordsWereScanned(value);
440 }
441
442 - (void)_resourceLoadStatisticsSetShouldClassifyResourcesBeforeDataRecordsRemoval:(BOOL)value
443 {
444     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
445     if (!store)
446         return;
447
448     store->setShouldClassifyResourcesBeforeDataRecordsRemoval(value);
449 }
450
451 - (void)_resourceLoadStatisticsSetNotifyPagesWhenTelemetryWasCaptured:(BOOL)value
452 {
453     WebKit::WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured(value);
454 }
455
456 - (void)_resourceLoadStatisticsSetShouldSubmitTelemetry:(BOOL)value
457 {
458     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
459     if (!store)
460         return;
461
462     store->setShouldSubmitTelemetry(value);
463 }
464
465 - (void)_resourceLoadStatisticsClearInMemoryAndPersistentStore
466 {
467     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
468     if (!store)
469         return;
470
471     store->scheduleClearInMemoryAndPersistent(WebKit::WebResourceLoadStatisticsStore::ShouldGrandfather::Yes);
472 }
473
474 - (void)_resourceLoadStatisticsClearInMemoryAndPersistentStoreModifiedSinceHours:(unsigned)hours
475 {
476     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
477     if (!store)
478         return;
479
480     store->scheduleClearInMemoryAndPersistent(std::chrono::system_clock::now() - std::chrono::hours(hours), WebKit::WebResourceLoadStatisticsStore::ShouldGrandfather::Yes);
481 }
482
483 - (void)_resourceLoadStatisticsResetToConsistentState
484 {
485     WebKit::WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured(false);
486
487     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
488     if (!store)
489         return;
490
491     store->resetParametersToDefaultValues();
492     store->scheduleClearInMemory();
493 }
494
495 - (void)_setResourceLoadStatisticsTestingCallback:(void (^)(WKWebsiteDataStore *, NSString *))callback
496 {
497     if (callback) {
498         _websiteDataStore->websiteDataStore().enableResourceLoadStatisticsAndSetTestingCallback([callback = makeBlockPtr(callback), self](const String& event) {
499             callback(self, (NSString *)event);
500         });
501         return;
502     }
503
504     auto* store = _websiteDataStore->websiteDataStore().resourceLoadStatistics();
505     if (!store)
506         return;
507
508     store->setStatisticsTestingCallback(nullptr);
509 }
510
511 @end
512
513 #endif // WK_API_ENABLED