5e277f9bd15768e85ffd21a27c544f198718120f
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / Cocoa / WKProcessPool.mm
1 /*
2  * Copyright (C) 2014 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 "WKProcessPoolInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "CacheModel.h"
32 #import "DownloadClient.h"
33 #import "HistoryClient.h"
34 #import "ProcessModel.h"
35 #import "SandboxUtilities.h"
36 #import "WKObject.h"
37 #import "WeakObjCPtr.h"
38 #import "WebCertificateInfo.h"
39 #import "WebContext.h"
40 #import "WebCookieManagerProxy.h"
41 #import "WebProcessMessages.h"
42 #import "_WKDownloadDelegate.h"
43 #import "_WKProcessPoolConfiguration.h"
44 #import <WebCore/CertificateInfo.h>
45 #import <wtf/RetainPtr.h>
46
47 #if PLATFORM(IOS)
48 #import <WebCore/WebCoreThreadSystemInterface.h>
49 #import "WKGeolocationProviderIOS.h"
50 #endif
51
52 #if __has_include(<CFNetwork/CFNSURLConnection.h>)
53 #import <CFNetwork/CFNSURLConnection.h>
54 #else
55 enum : NSUInteger {
56     NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain = 3,
57 };
58 #endif
59
60 @implementation WKProcessPool {
61     WebKit::WeakObjCPtr<id <_WKDownloadDelegate>> _downloadDelegate;
62
63 #if PLATFORM(IOS)
64     RetainPtr<WKGeolocationProviderIOS> _geolocationProvider;
65 #endif // PLATFORM(IOS)
66 }
67
68 - (instancetype)init
69 {
70     return [self _initWithConfiguration:adoptNS([[_WKProcessPoolConfiguration alloc] init]).get()];
71 }
72
73 - (void)dealloc
74 {
75     _context->~WebContext();
76
77     [super dealloc];
78 }
79
80 - (NSString *)description
81 {
82     return [NSString stringWithFormat:@"<%@: %p; configuration = %@>", NSStringFromClass(self.class), self, _configuration.get()];
83 }
84
85 - (_WKProcessPoolConfiguration *)_configuration
86 {
87     return [[_configuration copy] autorelease];
88 }
89
90 - (API::Object&)_apiObject
91 {
92     return *_context;
93 }
94
95 #if PLATFORM(IOS)
96 - (WKGeolocationProviderIOS *)_geolocationProvider
97 {
98     if (!_geolocationProvider)
99         _geolocationProvider = adoptNS([[WKGeolocationProviderIOS alloc] initWithContext:_context.get()]);
100     return _geolocationProvider.get();
101 }
102 #endif // PLATFORM(IOS)
103
104 @end
105
106 @implementation WKProcessPool (WKPrivate)
107
108 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL
109 {
110     return [WKProcessPool _websiteDataURLForContainerWithURL:containerURL bundleIdentifierIfNotInContainer:nil];
111 }
112
113 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL bundleIdentifierIfNotInContainer:(NSString *)bundleIdentifier
114 {
115     NSURL *url = [containerURL URLByAppendingPathComponent:@"Library" isDirectory:YES];
116     url = [url URLByAppendingPathComponent:@"WebKit" isDirectory:YES];
117
118     if (!WebKit::processHasContainer() && bundleIdentifier)
119         url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
120
121     return [url URLByAppendingPathComponent:@"WebsiteData" isDirectory:YES];
122 }
123
124 static NSURL *websiteDataDirectoryURL(NSString *directoryName)
125 {
126     static dispatch_once_t onceToken;
127     static NSURL *websiteDataURL;
128
129     dispatch_once(&onceToken, ^{
130         NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSLibraryDirectory inDomain:NSUserDomainMask appropriateForURL:nullptr create:NO error:nullptr];
131         if (!url)
132             RELEASE_ASSERT_NOT_REACHED();
133
134         url = [url URLByAppendingPathComponent:@"WebKit" isDirectory:YES];
135
136         if (!WebKit::processHasContainer()) {
137             NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
138             if (!bundleIdentifier)
139                 bundleIdentifier = [NSProcessInfo processInfo].processName;
140             url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
141         }
142
143         websiteDataURL = [[url URLByAppendingPathComponent:@"WebsiteData" isDirectory:YES] retain];
144     });
145
146     NSURL *url = [websiteDataURL URLByAppendingPathComponent:directoryName isDirectory:YES];
147     if (![[NSFileManager defaultManager] createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:nullptr])
148         LOG_ERROR("Failed to create directory %@", url);
149
150     return url;
151 }
152
153 - (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration
154 {
155     if (!(self = [super init]))
156         return nil;
157
158     _configuration = adoptNS([configuration copy]);
159
160 #if PLATFORM(IOS)
161     // FIXME: Remove once <rdar://problem/15256572> is fixed.
162     InitWebCoreThreadSystemInterface();
163 #endif
164
165     WebKit::WebContextConfiguration webContextConfiguration;
166
167     if (NSURL *bundleURL = [_configuration injectedBundleURL]) {
168         if (!bundleURL.isFileURL)
169             [NSException raise:NSInvalidArgumentException format:@"Injected Bundle URL must be a file URL"];
170
171         webContextConfiguration.injectedBundlePath = bundleURL.path;
172     }
173
174     webContextConfiguration.localStorageDirectory = websiteDataDirectoryURL(@"LocalStorage").absoluteURL.path.fileSystemRepresentation;
175     webContextConfiguration.webSQLDatabaseDirectory = websiteDataDirectoryURL(@"WebSQL").absoluteURL.path.fileSystemRepresentation;
176     webContextConfiguration.indexedDBDatabaseDirectory = websiteDataDirectoryURL(@"IndexedDB").absoluteURL.path.fileSystemRepresentation;
177
178     API::Object::constructInWrapper<WebKit::WebContext>(self, WTF::move(webContextConfiguration));
179     _context->setHistoryClient(std::make_unique<WebKit::HistoryClient>());
180     _context->setUsesNetworkProcess(true);
181     _context->setProcessModel(WebKit::ProcessModelMultipleSecondaryProcesses);
182     _context->setMaximumNumberOfProcesses([_configuration maximumProcessCount]);
183
184 #if ENABLE(CACHE_PARTITIONING)
185     for (NSString *urlScheme in [_configuration cachePartitionedURLSchemes])
186         _context->registerURLSchemeAsCachePartitioned(urlScheme);
187 #endif
188
189     // FIXME: Add a way to configure the cache model, see <rdar://problem/16206857>.
190     _context->setCacheModel(WebKit::CacheModelPrimaryWebBrowser);
191
192     return self;
193 }
194
195 - (void)_setAllowsSpecificHTTPSCertificate:(NSArray *)certificateChain forHost:(NSString *)host
196 {
197     _context->allowSpecificHTTPSCertificateForHost(WebKit::WebCertificateInfo::create(WebCore::CertificateInfo((CFArrayRef)certificateChain)).get(), host);
198 }
199
200 static WebKit::HTTPCookieAcceptPolicy toHTTPCookieAcceptPolicy(NSHTTPCookieAcceptPolicy policy)
201 {
202     switch (static_cast<NSUInteger>(policy)) {
203     case NSHTTPCookieAcceptPolicyAlways:
204         return WebKit::HTTPCookieAcceptPolicyAlways;
205     case NSHTTPCookieAcceptPolicyNever:
206         return WebKit::HTTPCookieAcceptPolicyNever;
207     case NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:
208         return WebKit::HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
209     case NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain:
210         return WebKit::HTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
211     }
212
213     ASSERT_NOT_REACHED();
214     return WebKit::HTTPCookieAcceptPolicyAlways;
215 }
216
217 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy
218 {
219     _context->supplement<WebKit::WebCookieManagerProxy>()->setHTTPCookieAcceptPolicy(toHTTPCookieAcceptPolicy(policy));
220 }
221
222 - (id)_objectForBundleParameter:(NSString *)parameter
223 {
224     return [_context->bundleParameters() objectForKey:parameter];
225 }
226
227 - (void)_setObject:(id <NSCopying, NSSecureCoding>)object forBundleParameter:(NSString *)parameter
228 {
229     auto copy = adoptNS([(NSObject *)object copy]);
230
231     auto data = adoptNS([[NSMutableData alloc] init]);
232     auto keyedArchiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
233     [keyedArchiver setRequiresSecureCoding:YES];
234
235     @try {
236         [keyedArchiver encodeObject:copy.get() forKey:@"parameter"];
237         [keyedArchiver finishEncoding];
238     } @catch (NSException *exception) {
239         LOG_ERROR("Failed to encode bundle parameter: %@", exception);
240     }
241
242     if (copy)
243         [_context->ensureBundleParameters() setObject:copy.get() forKey:parameter];
244     else
245         [_context->ensureBundleParameters() removeObjectForKey:parameter];
246
247     _context->sendToAllProcesses(Messages::WebProcess::SetInjectedBundleParameter(parameter, IPC::DataReference(static_cast<const uint8_t*>([data bytes]), [data length])));
248 }
249
250 - (id <_WKDownloadDelegate>)_downloadDelegate
251 {
252     return _downloadDelegate.getAutoreleased();
253 }
254
255 - (void)_setDownloadDelegate:(id <_WKDownloadDelegate>)downloadDelegate
256 {
257     _downloadDelegate = downloadDelegate;
258     _context->setDownloadClient(std::make_unique<WebKit::DownloadClient>(downloadDelegate));
259 }
260
261 @end
262
263 #endif // WK_API_ENABLED