Unreviewed, fix iOS build with recent SDKs.
[WebKit-https.git] / Source / WebKit / UIProcess / API / Cocoa / APIWebsiteDataStoreCocoa.mm
1 /*
2  * Copyright (C) 2014, 2016 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 #include "config.h"
27 #include "APIWebsiteDataStore.h"
28
29 #include "SandboxExtension.h"
30 #include "SandboxUtilities.h"
31 #include <Foundation/Foundation.h>
32 #include <wtf/FileSystem.h>
33
34 #if PLATFORM(IOS_FAMILY)
35 #import <WebCore/RuntimeApplicationChecks.h>
36 #endif
37
38 namespace API {
39
40 NSString *WebDatabaseDirectoryDefaultsKey = @"WebDatabaseDirectory";
41 NSString *WebStorageDirectoryDefaultsKey = @"WebKitLocalStorageDatabasePathPreferenceKey";
42 NSString *WebKitMediaCacheDirectoryDefaultsKey = @"WebKitMediaCacheDirectory";
43 NSString *WebKitMediaKeysStorageDirectoryDefaultsKey = @"WebKitMediaKeysStorageDirectory";
44
45 WTF::String WebsiteDataStore::defaultApplicationCacheDirectory()
46 {
47 #if PLATFORM(IOS_FAMILY)
48     // This quirk used to make these apps share application cache storage, but doesn't accomplish that any more.
49     // Preserving it avoids the need to migrate data when upgrading.
50     // FIXME: Ideally we should just have Safari, WebApp, and webbookmarksd create a data store with
51     // this application cache path, but that's not supported as of right now.
52     if (WebCore::IOSApplication::isMobileSafari() || WebCore::IOSApplication::isWebApp() || WebCore::IOSApplication::isWebBookmarksD()) {
53         NSString *cachePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/com.apple.WebAppCache"];
54
55         return WebKit::stringByResolvingSymlinksInPath(cachePath.stringByStandardizingPath);
56     }
57 #endif
58
59     return cacheDirectoryFileSystemRepresentation("OfflineWebApplicationCache");
60 }
61
62 WTF::String WebsiteDataStore::defaultCacheStorageDirectory()
63 {
64     return cacheDirectoryFileSystemRepresentation("CacheStorage");
65 }
66
67 WTF::String WebsiteDataStore::defaultNetworkCacheDirectory()
68 {
69     return cacheDirectoryFileSystemRepresentation("NetworkCache");
70 }
71
72 WTF::String WebsiteDataStore::defaultMediaCacheDirectory()
73 {
74     return tempDirectoryFileSystemRepresentation("MediaCache");
75 }
76
77 WTF::String WebsiteDataStore::defaultIndexedDBDatabaseDirectory()
78 {
79     return websiteDataDirectoryFileSystemRepresentation("IndexedDB");
80 }
81
82 WTF::String WebsiteDataStore::defaultServiceWorkerRegistrationDirectory()
83 {
84     return cacheDirectoryFileSystemRepresentation("ServiceWorkers");
85 }
86
87 WTF::String WebsiteDataStore::defaultLocalStorageDirectory()
88 {
89     return websiteDataDirectoryFileSystemRepresentation("LocalStorage");
90 }
91
92 WTF::String WebsiteDataStore::defaultMediaKeysStorageDirectory()
93 {
94     return websiteDataDirectoryFileSystemRepresentation("MediaKeys");
95 }
96
97 WTF::String WebsiteDataStore::defaultWebSQLDatabaseDirectory()
98 {
99     return websiteDataDirectoryFileSystemRepresentation("WebSQL");
100 }
101
102 WTF::String WebsiteDataStore::defaultResourceLoadStatisticsDirectory()
103 {
104     return websiteDataDirectoryFileSystemRepresentation("ResourceLoadStatistics");
105 }
106
107 WTF::String WebsiteDataStore::defaultJavaScriptConfigurationDirectory()
108 {
109     return tempDirectoryFileSystemRepresentation("JavaScriptCoreDebug", DontCreateDirectory);
110 }
111
112 WTF::String WebsiteDataStore::legacyDefaultApplicationCacheDirectory()
113 {
114     NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
115     if (!appName)
116         appName = [[NSProcessInfo processInfo] processName];
117 #if PLATFORM(IOS_FAMILY)
118     // This quirk used to make these apps share application cache storage, but doesn't accomplish that any more.
119     // Preserving it avoids the need to migrate data when upgrading.
120     if (WebCore::IOSApplication::isMobileSafari() || WebCore::IOSApplication::isWebApp())
121         appName = @"com.apple.WebAppCache";
122 #endif
123     
124     ASSERT(appName);
125     
126 #if PLATFORM(IOS_FAMILY)
127     NSString *cacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
128 #else
129     char cacheDirectory[MAXPATHLEN];
130     size_t cacheDirectoryLen = confstr(_CS_DARWIN_USER_CACHE_DIR, cacheDirectory, MAXPATHLEN);
131     if (!cacheDirectoryLen)
132         return WTF::String();
133     
134     NSString *cacheDir = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:cacheDirectory length:cacheDirectoryLen - 1];
135 #endif
136     NSString* cachePath = [cacheDir stringByAppendingPathComponent:appName];
137     return WebKit::stringByResolvingSymlinksInPath([cachePath stringByStandardizingPath]);
138 }
139
140 WTF::String WebsiteDataStore::legacyDefaultNetworkCacheDirectory()
141 {
142     NSString *cachePath = CFBridgingRelease(_CFURLCacheCopyCacheDirectory([[NSURLCache sharedURLCache] _CFURLCache]));
143     if (!cachePath)
144         cachePath = @"~/Library/Caches/com.apple.WebKit.WebProcess";
145     
146     cachePath = [cachePath stringByAppendingPathComponent:@"WebKitCache"];
147     
148     return WebKit::stringByResolvingSymlinksInPath([cachePath stringByStandardizingPath]);
149 }
150
151 WTF::String WebsiteDataStore::legacyDefaultWebSQLDatabaseDirectory()
152 {
153     NSString *databasesDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebDatabaseDirectoryDefaultsKey];
154     if (!databasesDirectory || ![databasesDirectory isKindOfClass:[NSString class]])
155         databasesDirectory = @"~/Library/WebKit/Databases";
156     return WebKit::stringByResolvingSymlinksInPath([databasesDirectory stringByStandardizingPath]);
157 }
158
159 WTF::String WebsiteDataStore::legacyDefaultIndexedDBDatabaseDirectory()
160 {
161     // Indexed databases exist in a subdirectory of the "database directory path."
162     // Currently, the top level of that directory contains entities related to WebSQL databases.
163     // We should fix this, and move WebSQL into a subdirectory (https://bugs.webkit.org/show_bug.cgi?id=124807)
164     // In the meantime, an entity name prefixed with three underscores will not conflict with any WebSQL entities.
165     return FileSystem::pathByAppendingComponent(legacyDefaultWebSQLDatabaseDirectory(), "___IndexedDB");
166 }
167
168 WTF::String WebsiteDataStore::legacyDefaultLocalStorageDirectory()
169 {
170     NSString *localStorageDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebStorageDirectoryDefaultsKey];
171     if (!localStorageDirectory || ![localStorageDirectory isKindOfClass:[NSString class]])
172         localStorageDirectory = @"~/Library/WebKit/LocalStorage";
173     return WebKit::stringByResolvingSymlinksInPath([localStorageDirectory stringByStandardizingPath]);
174 }
175
176 WTF::String WebsiteDataStore::legacyDefaultMediaCacheDirectory()
177 {
178     NSString *mediaKeysCacheDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitMediaCacheDirectoryDefaultsKey];
179     if (!mediaKeysCacheDirectory || ![mediaKeysCacheDirectory isKindOfClass:[NSString class]]) {
180         mediaKeysCacheDirectory = NSTemporaryDirectory();
181         
182         if (!WebKit::processHasContainer()) {
183             NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
184             if (!bundleIdentifier)
185                 bundleIdentifier = [NSProcessInfo processInfo].processName;
186             mediaKeysCacheDirectory = [mediaKeysCacheDirectory stringByAppendingPathComponent:bundleIdentifier];
187         }
188         mediaKeysCacheDirectory = [mediaKeysCacheDirectory stringByAppendingPathComponent:@"WebKit/MediaCache"];
189     }
190     return WebKit::stringByResolvingSymlinksInPath([mediaKeysCacheDirectory stringByStandardizingPath]);
191 }
192
193 WTF::String WebsiteDataStore::legacyDefaultMediaKeysStorageDirectory()
194 {
195     NSString *mediaKeysStorageDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitMediaKeysStorageDirectoryDefaultsKey];
196     if (!mediaKeysStorageDirectory || ![mediaKeysStorageDirectory isKindOfClass:[NSString class]])
197         mediaKeysStorageDirectory = @"~/Library/WebKit/MediaKeys";
198     return WebKit::stringByResolvingSymlinksInPath([mediaKeysStorageDirectory stringByStandardizingPath]);
199 }
200
201 WTF::String WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory()
202 {
203     // Not implemented.
204     return String();
205 }
206
207 WTF::String WebsiteDataStore::legacyDefaultJavaScriptConfigurationDirectory()
208 {
209 #if PLATFORM(IOS_FAMILY)
210     WTF::String path = WebKit::pathForProcessContainer();
211     if (path.isEmpty())
212         path = NSHomeDirectory();
213     
214     path = path + "/Library/WebKit/JavaScriptCoreDebug";
215     path = WebKit::stringByResolvingSymlinksInPath(path);
216     
217     return path;
218 #else
219     RetainPtr<NSString> javaScriptConfigPath = @"~/Library/WebKit/JavaScriptCoreDebug";
220     
221     return WebKit::stringByResolvingSymlinksInPath([javaScriptConfigPath stringByStandardizingPath]);
222 #endif
223 }
224
225 WTF::String WebsiteDataStore::tempDirectoryFileSystemRepresentation(const WTF::String& directoryName, ShouldCreateDirectory shouldCreateDirectory)
226 {
227     static dispatch_once_t onceToken;
228     static NSURL *tempURL;
229     
230     dispatch_once(&onceToken, ^{
231         NSURL *url = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
232         if (!url)
233             RELEASE_ASSERT_NOT_REACHED();
234         
235         if (!WebKit::processHasContainer()) {
236             NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
237             if (!bundleIdentifier)
238                 bundleIdentifier = [NSProcessInfo processInfo].processName;
239             url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
240         }
241         
242         tempURL = [[url URLByAppendingPathComponent:@"WebKit" isDirectory:YES] retain];
243     });
244     
245     NSURL *url = [tempURL URLByAppendingPathComponent:directoryName isDirectory:YES];
246
247     if (shouldCreateDirectory == CreateDirectory
248         && (![[NSFileManager defaultManager] createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:nullptr]))
249         LOG_ERROR("Failed to create directory %@", url);
250     
251     return url.absoluteURL.path.fileSystemRepresentation;
252 }
253
254 WTF::String WebsiteDataStore::cacheDirectoryFileSystemRepresentation(const WTF::String& directoryName)
255 {
256     static dispatch_once_t onceToken;
257     static NSURL *cacheURL;
258
259     dispatch_once(&onceToken, ^{
260         NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nullptr create:NO error:nullptr];
261         if (!url)
262             RELEASE_ASSERT_NOT_REACHED();
263
264         if (!WebKit::processHasContainer()) {
265             NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
266             if (!bundleIdentifier)
267                 bundleIdentifier = [NSProcessInfo processInfo].processName;
268             url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
269         }
270
271         cacheURL = [[url URLByAppendingPathComponent:@"WebKit" isDirectory:YES] retain];
272     });
273
274     NSURL *url = [cacheURL URLByAppendingPathComponent:directoryName isDirectory:YES];
275     if (![[NSFileManager defaultManager] createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:nullptr])
276         LOG_ERROR("Failed to create directory %@", url);
277
278     return url.absoluteURL.path.fileSystemRepresentation;
279 }
280
281 WTF::String WebsiteDataStore::websiteDataDirectoryFileSystemRepresentation(const WTF::String& directoryName)
282 {
283     static dispatch_once_t onceToken;
284     static NSURL *websiteDataURL;
285
286     dispatch_once(&onceToken, ^{
287         NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSLibraryDirectory inDomain:NSUserDomainMask appropriateForURL:nullptr create:NO error:nullptr];
288         if (!url)
289             RELEASE_ASSERT_NOT_REACHED();
290
291         url = [url URLByAppendingPathComponent:@"WebKit" isDirectory:YES];
292
293         if (!WebKit::processHasContainer()) {
294             NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
295             if (!bundleIdentifier)
296                 bundleIdentifier = [NSProcessInfo processInfo].processName;
297             url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
298         }
299
300         websiteDataURL = [[url URLByAppendingPathComponent:@"WebsiteData" isDirectory:YES] retain];
301     });
302
303     NSURL *url = [websiteDataURL URLByAppendingPathComponent:directoryName isDirectory:YES];
304     if (![[NSFileManager defaultManager] createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:nullptr])
305         LOG_ERROR("Failed to create directory %@", url);
306
307     return url.absoluteURL.path.fileSystemRepresentation;
308 }
309
310 } // namespace API