Plugin processes are repeatedly spun up to do nothing
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / WKHTTPCookieStore.mm
1 /*
2  * Copyright (C) 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 #include "config.h"
27
28 #import "PlatformUtilities.h"
29 #import "TestNavigationDelegate.h"
30 #import <WebKit/WKFoundation.h>
31 #import <WebKit/WKHTTPCookieStore.h>
32 #import <WebKit/WKProcessPoolPrivate.h>
33 #import <WebKit/WKWebsiteDataStorePrivate.h>
34 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
35 #import <wtf/RetainPtr.h>
36
37 #if WK_API_ENABLED
38
39 static bool gotFlag;
40 static uint64_t observerCallbacks;
41 static RetainPtr<WKHTTPCookieStore> globalCookieStore;
42
43 @interface CookieObserver : NSObject<WKHTTPCookieStoreObserver>
44 - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore;
45 @end
46
47 @implementation CookieObserver
48
49 - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore
50 {
51     ASSERT_EQ(cookieStore, globalCookieStore.get());
52     ++observerCallbacks;
53 }
54
55 @end
56
57 static void runTestWithWebsiteDataStore(WKWebsiteDataStore* dataStore)
58 {
59     observerCallbacks = 0;
60
61     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
62     configuration.get().websiteDataStore = dataStore;
63     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
64
65     [webView loadHTMLString:@"Oh hello" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
66     [webView _test_waitForDidFinishNavigation];
67
68     [dataStore removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:[] {
69         gotFlag = true;
70     }];
71
72     TestWebKitAPI::Util::run(&gotFlag);
73     gotFlag = false;
74
75     // Triggering removeData when we don't have plugin data to remove should not trigger the plugin process to launch.
76     id pool = [WKProcessPool _sharedProcessPool];
77     EXPECT_EQ([pool _pluginProcessCount], static_cast<size_t>(0));
78
79     globalCookieStore = dataStore.httpCookieStore;
80     RetainPtr<CookieObserver> observer1 = adoptNS([[CookieObserver alloc] init]);
81     RetainPtr<CookieObserver> observer2 = adoptNS([[CookieObserver alloc] init]);
82     [globalCookieStore addObserver:observer1.get()];
83     [globalCookieStore addObserver:observer2.get()];
84
85     NSArray<NSHTTPCookie *> *cookies = nil;
86     [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
87         *cookiesPtr = [nsCookies retain];
88         gotFlag = true;
89     }];
90
91     TestWebKitAPI::Util::run(&gotFlag);
92
93     ASSERT_EQ(cookies.count, 0u);
94     [cookies release];
95
96     gotFlag = false;
97
98     RetainPtr<NSHTTPCookie> cookie1 = [NSHTTPCookie cookieWithProperties:@{
99         NSHTTPCookiePath: @"/",
100         NSHTTPCookieName: @"CookieName",
101         NSHTTPCookieValue: @"CookieValue",
102         NSHTTPCookieDomain: @".www.webkit.org",
103         NSHTTPCookieSecure: @"TRUE",
104         NSHTTPCookieDiscard: @"TRUE",
105         NSHTTPCookieMaximumAge: @"10000",
106     }];
107
108     RetainPtr<NSHTTPCookie> cookie2 = [NSHTTPCookie cookieWithProperties:@{
109         NSHTTPCookiePath: @"/path",
110         NSHTTPCookieName: @"OtherCookieName",
111         NSHTTPCookieValue: @"OtherCookieValue",
112         NSHTTPCookieDomain: @".www.w3c.org",
113         NSHTTPCookieMaximumAge: @"10000",
114     }];
115
116     [globalCookieStore setCookie:cookie1.get() completionHandler:[](){
117         gotFlag = true;
118     }];
119
120     TestWebKitAPI::Util::run(&gotFlag);
121     gotFlag = false;
122
123     [globalCookieStore setCookie:cookie2.get() completionHandler:[](){
124         gotFlag = true;
125     }];
126
127     TestWebKitAPI::Util::run(&gotFlag);
128     gotFlag = false;
129
130     [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
131         *cookiesPtr = [nsCookies retain];
132         gotFlag = true;
133     }];
134
135     TestWebKitAPI::Util::run(&gotFlag);
136     gotFlag = false;
137
138     ASSERT_EQ(cookies.count, 2u);
139     ASSERT_EQ(observerCallbacks, 4u);
140
141     for (NSHTTPCookie *cookie : cookies) {
142         if ([cookie.name isEqual:@"CookieName"]) {
143             ASSERT_TRUE([cookie1.get().path isEqualToString:cookie.path]);
144             ASSERT_TRUE([cookie1.get().value isEqualToString:cookie.value]);
145             ASSERT_TRUE([cookie1.get().domain isEqualToString:cookie.domain]);
146             ASSERT_TRUE(cookie.secure);
147             ASSERT_TRUE(cookie.sessionOnly);
148         } else {
149             ASSERT_TRUE([cookie2.get().path isEqualToString:cookie.path]);
150             ASSERT_TRUE([cookie2.get().value isEqualToString:cookie.value]);
151             ASSERT_TRUE([cookie2.get().name isEqualToString:cookie.name]);
152             ASSERT_TRUE([cookie2.get().domain isEqualToString:cookie.domain]);
153             ASSERT_FALSE(cookie.secure);
154             ASSERT_FALSE(cookie.sessionOnly);
155         }
156     }
157     [cookies release];
158
159     [globalCookieStore deleteCookie:cookie2.get() completionHandler:[](){
160         gotFlag = true;
161     }];
162
163     TestWebKitAPI::Util::run(&gotFlag);
164     gotFlag = false;
165
166     [globalCookieStore getAllCookies:[cookiesPtr = &cookies](NSArray<NSHTTPCookie *> *nsCookies) {
167         *cookiesPtr = [nsCookies retain];
168         gotFlag = true;
169     }];
170
171     TestWebKitAPI::Util::run(&gotFlag);
172     gotFlag = false;
173
174     ASSERT_EQ(cookies.count, 1u);
175     ASSERT_EQ(observerCallbacks, 6u);
176
177     for (NSHTTPCookie *cookie : cookies) {
178         ASSERT_TRUE([cookie1.get().path isEqualToString:cookie.path]);
179         ASSERT_TRUE([cookie1.get().value isEqualToString:cookie.value]);
180         ASSERT_TRUE([cookie1.get().domain isEqualToString:cookie.domain]);
181         ASSERT_TRUE(cookie.secure);
182         ASSERT_TRUE(cookie.sessionOnly);
183     }
184     [cookies release];
185
186     [globalCookieStore removeObserver:observer1.get()];
187     [globalCookieStore removeObserver:observer2.get()];
188 }
189
190 TEST(WebKit, WKHTTPCookieStore)
191 {
192     runTestWithWebsiteDataStore([WKWebsiteDataStore defaultDataStore]);
193 }
194
195 // FIXME: This should be removed once <rdar://problem/35344202> is resolved and bots are updated.
196 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED <= 110102)
197 TEST(WebKit, WKHTTPCookieStoreNonPersistent)
198 {
199     RetainPtr<WKWebsiteDataStore> nonPersistentDataStore;
200     @autoreleasepool {
201         nonPersistentDataStore = [WKWebsiteDataStore nonPersistentDataStore];
202     }
203
204     runTestWithWebsiteDataStore(nonPersistentDataStore.get());
205 }
206
207 TEST(WebKit, WKHTTPCookieStoreCustom)
208 {
209     NSURL *cookieStorageFile = [NSURL fileURLWithPath:[@"~/Library/WebKit/TestWebKitAPI/CustomWebsiteData/CookieStorage/Cookie.File" stringByExpandingTildeInPath] isDirectory:NO];
210     NSURL *idbPath = [NSURL fileURLWithPath:[@"~/Library/WebKit/TestWebKitAPI/CustomWebsiteData/IndexedDB/" stringByExpandingTildeInPath] isDirectory:YES];
211
212     [[NSFileManager defaultManager] removeItemAtURL:cookieStorageFile error:nil];
213     [[NSFileManager defaultManager] removeItemAtURL:idbPath error:nil];
214
215     EXPECT_FALSE([[NSFileManager defaultManager] fileExistsAtPath:cookieStorageFile.path]);
216     EXPECT_FALSE([[NSFileManager defaultManager] fileExistsAtPath:idbPath.path]);
217
218     auto websiteDataStoreConfiguration = adoptNS([[_WKWebsiteDataStoreConfiguration alloc] init]);
219     websiteDataStoreConfiguration.get()._indexedDBDatabaseDirectory = idbPath;
220     websiteDataStoreConfiguration.get()._cookieStorageFile = cookieStorageFile;
221
222     auto customDataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:websiteDataStoreConfiguration.get()]);
223     runTestWithWebsiteDataStore(customDataStore.get());
224 }
225 #endif // (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED <= 110102)
226
227 TEST(WebKit, CookieObserverCrash)
228 {
229     RetainPtr<WKWebsiteDataStore> nonPersistentDataStore;
230     @autoreleasepool {
231         nonPersistentDataStore = [WKWebsiteDataStore nonPersistentDataStore];
232     }
233
234     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
235     configuration.get().websiteDataStore = nonPersistentDataStore.get();
236
237     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
238
239     [webView loadHTMLString:@"Oh hello" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
240     [webView _test_waitForDidFinishNavigation];
241
242     globalCookieStore = nonPersistentDataStore.get().httpCookieStore;
243     RetainPtr<CookieObserver> observer = adoptNS([[CookieObserver alloc] init]);
244     [globalCookieStore addObserver:observer.get()];
245
246     [globalCookieStore getAllCookies:[](NSArray<NSHTTPCookie *> *) {
247         gotFlag = true;
248     }];
249
250     TestWebKitAPI::Util::run(&gotFlag);
251 }
252
253 static bool finished;
254
255 @interface CookieUIDelegate : NSObject <WKUIDelegate>
256 @end
257
258 @implementation CookieUIDelegate
259 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
260 {
261     EXPECT_STREQ("cookie:cookiename=cookievalue", message.UTF8String);
262     finished = true;
263     completionHandler();
264 }
265 @end
266
267 // FIXME: This should be removed once <rdar://problem/35344202> is resolved and bots are updated.
268 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED <= 110102)
269 TEST(WebKit, WKHTTPCookieStoreWithoutProcessPool)
270 {
271     NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:[NSDictionary dictionaryWithObjectsAndKeys:@"127.0.0.1", NSHTTPCookieDomain, @"/", NSHTTPCookiePath, @"cookiename", NSHTTPCookieName, @"cookievalue", NSHTTPCookieValue, [NSDate distantFuture], NSHTTPCookieExpires, nil]];
272     NSString *alertCookieHTML = @"<script>alert('cookie:'+document.cookie);</script>";
273     
274     finished = false;
275     WKWebsiteDataStore *ephemeralStoreWithCookies = [WKWebsiteDataStore nonPersistentDataStore];
276     [ephemeralStoreWithCookies.httpCookieStore setCookie:cookie completionHandler:^ {
277         WKWebsiteDataStore *ephemeralStoreWithIndependentCookieStorage = [WKWebsiteDataStore nonPersistentDataStore];
278         [ephemeralStoreWithIndependentCookieStorage.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *cookies) {
279             ASSERT_EQ(cookies.count, 0u);
280             
281             WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
282             configuration.websiteDataStore = ephemeralStoreWithCookies;
283             WKWebView *view = [[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration];
284             view.UIDelegate = [[CookieUIDelegate alloc] init];
285
286             [view loadHTMLString:alertCookieHTML baseURL:[NSURL URLWithString:@"http://127.0.0.1/"]];
287         }];
288     }];
289     TestWebKitAPI::Util::run(&finished);
290     
291     // FIXME: Get this to work on iOS. <rdar://problem/32260156>
292 #if !PLATFORM(IOS)
293     finished = false;
294     WKWebsiteDataStore *defaultStore = [WKWebsiteDataStore defaultDataStore];
295     [defaultStore.httpCookieStore setCookie:cookie completionHandler:^ {
296         [defaultStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *cookies) {
297             ASSERT_EQ(cookies.count, 1u);
298             
299             WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
300             configuration.websiteDataStore = defaultStore;
301             WKWebView *view = [[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration];
302             view.UIDelegate = [[CookieUIDelegate alloc] init];
303             
304             [view loadHTMLString:alertCookieHTML baseURL:[NSURL URLWithString:@"http://127.0.0.1/"]];
305         }];
306     }];
307     TestWebKitAPI::Util::run(&finished);
308     
309     [defaultStore.httpCookieStore deleteCookie:cookie completionHandler:^ {
310         [defaultStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *cookies) {
311             ASSERT_EQ(cookies.count, 0u);
312             finished = true;
313         }];
314     }];
315     TestWebKitAPI::Util::run(&finished);
316 #endif
317 }
318 #endif // (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED <= 110102)
319 #endif