/* * Copyright (C) 2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "HTTPServer.h" #import "PlatformUtilities.h" #import "TestNavigationDelegate.h" #import "TestWKWebView.h" #import #import #import #import #import #import #import #import #import #import #import static bool gotFlag; static uint64_t observerCallbacks; static RetainPtr globalCookieStore; @interface CookieObserver : NSObject - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore; @end @implementation CookieObserver - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore { ASSERT_EQ(cookieStore, globalCookieStore.get()); ++observerCallbacks; } @end static void runTestWithWebsiteDataStore(WKWebsiteDataStore* dataStore) { observerCallbacks = 0; auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = dataStore; auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); [webView loadHTMLString:@"Oh hello" baseURL:[NSURL URLWithString:@"http://webkit.org"]]; [webView _test_waitForDidFinishNavigation]; [dataStore removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:[] { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; // Triggering removeData when we don't have plugin data to remove should not trigger the plugin process to launch. id pool = [WKProcessPool _sharedProcessPool]; EXPECT_EQ([pool _pluginProcessCount], static_cast(0)); globalCookieStore = dataStore.httpCookieStore; RetainPtr observer1 = adoptNS([[CookieObserver alloc] init]); RetainPtr observer2 = adoptNS([[CookieObserver alloc] init]); [globalCookieStore addObserver:observer1.get()]; [globalCookieStore addObserver:observer2.get()]; RetainPtr> cookies; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); ASSERT_EQ([cookies count], 0u); gotFlag = false; RetainPtr cookie1 = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"CookieName", NSHTTPCookieValue: @"CookieValue", NSHTTPCookieDomain: @".www.webkit.org", NSHTTPCookieSecure: @"TRUE", NSHTTPCookieDiscard: @"TRUE", NSHTTPCookieMaximumAge: @"10000", }]; RetainPtr cookie2 = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/path", NSHTTPCookieName: @"OtherCookieName", NSHTTPCookieValue: @"OtherCookieValue", NSHTTPCookieDomain: @".www.w3c.org", NSHTTPCookieMaximumAge: @"10000", }]; [globalCookieStore setCookie:cookie1.get() completionHandler:[](){ gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore setCookie:cookie2.get() completionHandler:[](){ gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 2u); while (observerCallbacks != 4u) TestWebKitAPI::Util::spinRunLoop(); for (NSHTTPCookie *cookie : cookies.get()) { if ([cookie.name isEqual:@"CookieName"]) { ASSERT_TRUE([cookie1.get().path isEqualToString:cookie.path]); ASSERT_TRUE([cookie1.get().value isEqualToString:cookie.value]); ASSERT_TRUE([cookie1.get().domain isEqualToString:cookie.domain]); ASSERT_TRUE(cookie.secure); ASSERT_TRUE(cookie.sessionOnly); } else { ASSERT_TRUE([cookie2.get().path isEqualToString:cookie.path]); ASSERT_TRUE([cookie2.get().value isEqualToString:cookie.value]); ASSERT_TRUE([cookie2.get().name isEqualToString:cookie.name]); ASSERT_TRUE([cookie2.get().domain isEqualToString:cookie.domain]); ASSERT_FALSE(cookie.secure); ASSERT_FALSE(cookie.sessionOnly); } } [globalCookieStore deleteCookie:cookie2.get() completionHandler:[](){ gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 1u); while (observerCallbacks != 6u) TestWebKitAPI::Util::spinRunLoop(); for (NSHTTPCookie *cookie : cookies.get()) { ASSERT_TRUE([cookie1.get().path isEqualToString:cookie.path]); ASSERT_TRUE([cookie1.get().value isEqualToString:cookie.value]); ASSERT_TRUE([cookie1.get().domain isEqualToString:cookie.domain]); ASSERT_TRUE(cookie.secure); ASSERT_TRUE(cookie.sessionOnly); } [globalCookieStore removeObserver:observer1.get()]; [globalCookieStore removeObserver:observer2.get()]; } TEST(WKHTTPCookieStore, Basic) { runTestWithWebsiteDataStore([WKWebsiteDataStore defaultDataStore]); } TEST(WKHTTPCookieStore, ProcessPrivilege) { // Make sure UI process has no privilege at the beginning. WTF::setProcessPrivileges({ }); [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:[] { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; globalCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; RetainPtr cookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"Cookie", NSHTTPCookieValue: @"Value", NSHTTPCookieDomain: @".www.webkit.org", }]; [globalCookieStore setCookie:cookie.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:^(NSArray*cookies) { ASSERT_EQ(1u, cookies.count); gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; } TEST(WKHTTPCookieStore, HttpOnly) { WKWebsiteDataStore* dataStore = [WKWebsiteDataStore defaultDataStore]; auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = dataStore; auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]]; [webView _test_waitForDidFinishNavigation]; [dataStore removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:[] { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; globalCookieStore = dataStore.httpCookieStore; RetainPtr> cookies; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 0u); auto cookieProperties = adoptNS([[NSMutableDictionary alloc] init]); [cookieProperties setObject:@"cookieName" forKey:NSHTTPCookieName]; [cookieProperties setObject:@"cookieValue" forKey:NSHTTPCookieValue]; [cookieProperties setObject:@".www.webkit.org" forKey:NSHTTPCookieDomain]; [cookieProperties setObject:@"/path" forKey:NSHTTPCookiePath]; [cookieProperties setObject:@YES forKey:@"HttpOnly"]; RetainPtr httpOnlyCookie = [NSHTTPCookie cookieWithProperties:cookieProperties.get()]; [cookieProperties setObject:@"cookieValue2" forKey:NSHTTPCookieValue]; RetainPtr httpOnlyCookie2 = [NSHTTPCookie cookieWithProperties:cookieProperties.get()]; [cookieProperties removeObjectForKey:@"HttpOnly"]; RetainPtr notHttpOnlyCookie = [NSHTTPCookie cookieWithProperties:cookieProperties.get()]; EXPECT_TRUE(httpOnlyCookie.get().HTTPOnly); EXPECT_FALSE(notHttpOnlyCookie.get().HTTPOnly); // Setting httpOnlyCookie should succeed. [globalCookieStore setCookie:httpOnlyCookie.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; // Setting httpOnlyCookie2 should succeed. [globalCookieStore setCookie:httpOnlyCookie2.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 1u); EXPECT_TRUE([[[cookies objectAtIndex:0] value] isEqual:@"cookieValue2"]); // Setting notHttpOnlyCookie should fail because we cannot overwrite HTTPOnly property using public API. [globalCookieStore setCookie:notHttpOnlyCookie.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 1u); EXPECT_TRUE([[cookies objectAtIndex:0] isHTTPOnly]); // Deleting notHttpOnlyCookie should fail because the cookie stored is HTTPOnly. [globalCookieStore deleteCookie:notHttpOnlyCookie.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 1u); // Deleting httpOnlyCookie should succeed. [globalCookieStore deleteCookie:httpOnlyCookie.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *nsCookies) { cookies = nsCookies; gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; ASSERT_EQ([cookies count], 0u); } // FIXME: Would be good to enable this test for watchOS and tvOS. #if !PLATFORM(WATCHOS) && !PLATFORM(APPLETV) TEST(WKHTTPCookieStore, CreationTime) { auto dataStore = [WKWebsiteDataStore defaultDataStore]; auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = dataStore; auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]]; [webView _test_waitForDidFinishNavigation]; [dataStore removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:[] { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; globalCookieStore = dataStore.httpCookieStore; auto cookieProperties = adoptNS([[NSMutableDictionary alloc] init]); [cookieProperties setObject:@"cookieName" forKey:NSHTTPCookieName]; [cookieProperties setObject:@"cookieValue" forKey:NSHTTPCookieValue]; [cookieProperties setObject:@".www.webkit.org" forKey:NSHTTPCookieDomain]; [cookieProperties setObject:@"/path" forKey:NSHTTPCookiePath]; RetainPtr creationTime = @(100000); [cookieProperties setObject:creationTime.get() forKey:@"Created"]; RetainPtr cookie = [NSHTTPCookie cookieWithProperties:cookieProperties.get()]; [globalCookieStore setCookie:cookie.get() completionHandler:[]() { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; [globalCookieStore getAllCookies:[&](NSArray *cookies) { ASSERT_EQ(1u, cookies.count); NSNumber* createdTime = [cookies objectAtIndex:0].properties[@"Created"]; EXPECT_TRUE([creationTime.get() isEqual:createdTime]); gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; sleep(1_s); [globalCookieStore getAllCookies:^(NSArray *cookies) { ASSERT_EQ(1u, cookies.count); NSNumber* createdTime = [cookies objectAtIndex:0].properties[@"Created"]; EXPECT_TRUE([creationTime.get() isEqual:createdTime]); gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); gotFlag = false; } #endif // FIXME: This #if should be removed once is resolved and bots are updated. #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301 TEST(WKHTTPCookieStore, NonPersistent) { RetainPtr nonPersistentDataStore; @autoreleasepool { nonPersistentDataStore = [WKWebsiteDataStore nonPersistentDataStore]; } runTestWithWebsiteDataStore(nonPersistentDataStore.get()); } TEST(WKHTTPCookieStore, Custom) { NSURL *cookieStorageFile = [NSURL fileURLWithPath:[@"~/Library/WebKit/com.apple.WebKit.TestWebKitAPI/CustomWebsiteData/CookieStorage/Cookie.File" stringByExpandingTildeInPath] isDirectory:NO]; NSURL *idbPath = [NSURL fileURLWithPath:[@"~/Library/WebKit/com.apple.WebKit.TestWebKitAPI/CustomWebsiteData/IndexedDB/" stringByExpandingTildeInPath] isDirectory:YES]; [[NSFileManager defaultManager] removeItemAtURL:cookieStorageFile error:nil]; [[NSFileManager defaultManager] removeItemAtURL:idbPath error:nil]; EXPECT_FALSE([[NSFileManager defaultManager] fileExistsAtPath:cookieStorageFile.path]); EXPECT_FALSE([[NSFileManager defaultManager] fileExistsAtPath:idbPath.path]); auto websiteDataStoreConfiguration = adoptNS([[_WKWebsiteDataStoreConfiguration alloc] init]); websiteDataStoreConfiguration.get()._indexedDBDatabaseDirectory = idbPath; websiteDataStoreConfiguration.get()._cookieStorageFile = cookieStorageFile; auto customDataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:websiteDataStoreConfiguration.get()]); runTestWithWebsiteDataStore(customDataStore.get()); } #endif // PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301 TEST(WebKit, CookieObserverCrash) { RetainPtr nonPersistentDataStore; @autoreleasepool { nonPersistentDataStore = [WKWebsiteDataStore nonPersistentDataStore]; } auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = nonPersistentDataStore.get(); auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); [webView loadHTMLString:@"Oh hello" baseURL:[NSURL URLWithString:@"http://webkit.org"]]; [webView _test_waitForDidFinishNavigation]; globalCookieStore = nonPersistentDataStore.get().httpCookieStore; RetainPtr observer = adoptNS([[CookieObserver alloc] init]); [globalCookieStore addObserver:observer.get()]; [globalCookieStore getAllCookies:[](NSArray *) { gotFlag = true; }]; TestWebKitAPI::Util::run(&gotFlag); } static void clearCookies(WKWebsiteDataStore *dataStore) { __block bool deleted = false; [dataStore removeDataOfTypes:[NSSet setWithObject:WKWebsiteDataTypeCookies] modifiedSince:[NSDate distantPast] completionHandler:^{ deleted = true; }]; TestWebKitAPI::Util::run(&deleted); } TEST(WKHTTPCookieStore, ObserveCookiesReceivedFromHTTP) { TestWebKitAPI::HTTPServer server({{ "/"_s, {{{ "Set-Cookie"_s, "testkey=testvalue"_s }}, "hello"_s }}}); auto runTest = [&] (WKWebsiteDataStore *dataStore) { auto configuration = adoptNS([WKWebViewConfiguration new]); configuration.get().websiteDataStore = dataStore; auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]); auto observer = adoptNS([CookieObserver new]); globalCookieStore = webView.get().configuration.websiteDataStore.httpCookieStore; clearCookies(dataStore); [globalCookieStore addObserver:observer.get()]; observerCallbacks = 0; [webView loadRequest:server.request()]; [webView _test_waitForDidFinishNavigation]; while (!observerCallbacks) TestWebKitAPI::Util::spinRunLoop(); __block bool gotCookie = false; [globalCookieStore getAllCookies:^(NSArray *cookies) { RELEASE_ASSERT(cookies.count == 1u); EXPECT_WK_STREQ(cookies[0].name, "testkey"); EXPECT_WK_STREQ(cookies[0].value, "testvalue"); gotCookie = true; }]; TestWebKitAPI::Util::run(&gotCookie); EXPECT_EQ(observerCallbacks, 1u); }; runTest([WKWebsiteDataStore defaultDataStore]); runTest([WKWebsiteDataStore nonPersistentDataStore]); } static bool finished; @interface CookieUIDelegate : NSObject @end @implementation CookieUIDelegate - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { EXPECT_STREQ("PersistentCookieName=CookieValue; SessionCookieName=CookieValue", message.UTF8String); finished = true; completionHandler(); } @end enum class ShouldEnableProcessPrewarming { No, Yes }; void runWKHTTPCookieStoreWithoutProcessPool(ShouldEnableProcessPrewarming shouldEnableProcessPrewarming) { RetainPtr sessionCookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"SessionCookieName", NSHTTPCookieValue: @"CookieValue", NSHTTPCookieDomain: @"127.0.0.1", }]; RetainPtr persistentCookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"PersistentCookieName", NSHTTPCookieValue: @"CookieValue", NSHTTPCookieDomain: @"127.0.0.1", NSHTTPCookieExpires: [NSDate distantFuture], }]; NSString *alertCookieHTML = @""; // NonPersistentDataStore RetainPtr ephemeralStoreWithCookies = [WKWebsiteDataStore nonPersistentDataStore]; finished = false; [ephemeralStoreWithCookies.get().httpCookieStore setCookie:persistentCookie.get() completionHandler:^{ WKWebsiteDataStore *ephemeralStoreWithIndependentCookieStorage = [WKWebsiteDataStore nonPersistentDataStore]; [ephemeralStoreWithIndependentCookieStorage.httpCookieStore getAllCookies:^(NSArray *cookies) { ASSERT_EQ(0u, cookies.count); finished = true; }]; }]; TestWebKitAPI::Util::run(&finished); finished = false; [ephemeralStoreWithCookies.get().httpCookieStore setCookie:sessionCookie.get() completionHandler:^{ [ephemeralStoreWithCookies.get().httpCookieStore getAllCookies:^(NSArray *cookies) { ASSERT_EQ(2u, cookies.count); finished = true; }]; }]; TestWebKitAPI::Util::run(&finished); finished = false; auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]); processPoolConfiguration.get().prewarmsProcessesAutomatically = shouldEnableProcessPrewarming == ShouldEnableProcessPrewarming::Yes; auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = ephemeralStoreWithCookies.get(); [configuration setProcessPool:processPool.get()]; auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); auto delegate = adoptNS([[CookieUIDelegate alloc] init]); webView.get().UIDelegate = delegate.get(); [webView loadHTMLString:alertCookieHTML baseURL:[NSURL URLWithString:@"http://127.0.0.1"]]; TestWebKitAPI::Util::run(&finished); finished = false; [ephemeralStoreWithCookies.get().httpCookieStore deleteCookie:sessionCookie.get() completionHandler:^{ [ephemeralStoreWithCookies.get().httpCookieStore getAllCookies:^(NSArray *cookies) { ASSERT_EQ(1u, cookies.count); finished = true; }]; }]; TestWebKitAPI::Util::run(&finished); // DefaultDataStore auto defaultStore = [WKWebsiteDataStore defaultDataStore]; finished = false; [defaultStore removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:[] { finished = true; }]; TestWebKitAPI::Util::run(&finished); finished = false; [defaultStore.httpCookieStore setCookie:persistentCookie.get() completionHandler:^{ [defaultStore.httpCookieStore getAllCookies:^(NSArray *cookies) { ASSERT_EQ(1u, cookies.count); finished = true; }]; }]; TestWebKitAPI::Util::run(&finished); finished = false; [defaultStore.httpCookieStore setCookie:sessionCookie.get() completionHandler:^{ [defaultStore.httpCookieStore getAllCookies:^(NSArray *cookies) { ASSERT_EQ(2u, cookies.count); finished = true; }]; }]; TestWebKitAPI::Util::run(&finished); finished = false; configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = defaultStore; webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); webView.get().UIDelegate = delegate.get(); [webView loadHTMLString:alertCookieHTML baseURL:[NSURL URLWithString:@"http://127.0.0.1"]]; TestWebKitAPI::Util::run(&finished); } TEST(WKHTTPCookieStore, WithoutProcessPoolWithoutPrewarming) { runWKHTTPCookieStoreWithoutProcessPool(ShouldEnableProcessPrewarming::No); } TEST(WKHTTPCookieStore, WithoutProcessPoolWithPrewarming) { runWKHTTPCookieStoreWithoutProcessPool(ShouldEnableProcessPrewarming::Yes); } @interface CheckSessionCookieUIDelegate : NSObject - (NSString *)alertCookieHTML; - (NSString *)waitForMessage; @end @implementation CheckSessionCookieUIDelegate { RetainPtr _message; } - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { _message = message; finished = true; completionHandler(); } - (NSString *)waitForMessage { while (!_message) TestWebKitAPI::Util::spinRunLoop(); return _message.autorelease(); } - (NSString *)alertCookieHTML { return @""; } @end TEST(WebKit, WKHTTPCookieStoreMultipleViews) { auto webView1 = adoptNS([TestWKWebView new]); [webView1 synchronouslyLoadHTMLString:@"start network process"]; NSHTTPCookie *sessionCookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"SessionCookieName", NSHTTPCookieValue: @"CookieValue", NSHTTPCookieDomain: @"127.0.0.1", }]; __block bool setCookieDone = false; [[webView1 configuration].websiteDataStore.httpCookieStore setCookie:sessionCookie completionHandler:^{ setCookieDone = true; }]; TestWebKitAPI::Util::run(&setCookieDone); auto delegate = adoptNS([CheckSessionCookieUIDelegate new]); [webView1 setUIDelegate:delegate.get()]; [webView1 loadHTMLString:[delegate alertCookieHTML] baseURL:[NSURL URLWithString:@"http://127.0.0.1"]]; EXPECT_WK_STREQ([delegate waitForMessage], "SessionCookieName=CookieValue"); auto webView2 = adoptNS([TestWKWebView new]); [webView2 setUIDelegate:delegate.get()]; [webView2 loadHTMLString:[delegate alertCookieHTML] baseURL:[NSURL URLWithString:@"http://127.0.0.1"]]; EXPECT_WK_STREQ([delegate waitForMessage], "SessionCookieName=CookieValue"); } TEST(WKHTTPCookieStore, WithoutProcessPoolEphemeralSession) { RetainPtr ephemeralStoreWithCookies = [WKWebsiteDataStore nonPersistentDataStore]; auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); configuration.get().websiteDataStore = ephemeralStoreWithCookies.get(); auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); auto delegate = adoptNS([[CheckSessionCookieUIDelegate alloc] init]); webView.get().UIDelegate = delegate.get(); RetainPtr sessionCookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"SessionCookieName", NSHTTPCookieValue: @"CookieValue", NSHTTPCookieDomain: @"127.0.0.1", }]; [ephemeralStoreWithCookies.get().httpCookieStore setCookie:sessionCookie.get() completionHandler:^{ finished = true; }]; TestWebKitAPI::Util::run(&finished); finished = false; [webView loadHTMLString:[delegate alertCookieHTML] baseURL:[NSURL URLWithString:@"http://127.0.0.1"]]; EXPECT_WK_STREQ([delegate waitForMessage], "SessionCookieName=CookieValue"); } static bool areCookiesEqual(NSHTTPCookie *first, NSHTTPCookie *second) { return [first.name isEqual:second.name] && [first.domain isEqual:second.domain] && [first.path isEqual:second.path] && [first.value isEqual:second.value]; } TEST(WKHTTPCookieStore, WithoutProcessPoolDuplicates) { RetainPtr httpCookieStore = [WKWebsiteDataStore defaultDataStore].httpCookieStore; RetainPtr sessionCookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"SessionCookieName", NSHTTPCookieValue: @"CookieValue", NSHTTPCookieDomain: @"127.0.0.1", }]; auto properties = adoptNS([sessionCookie.get().properties mutableCopy]); properties.get()[NSHTTPCookieDomain] = @"localhost"; RetainPtr sessionCookieDifferentDomain = [NSHTTPCookie cookieWithProperties:properties.get()]; properties.get()[NSHTTPCookieValue] = @"OtherCookieValue"; RetainPtr sessionCookieDifferentValue = [NSHTTPCookie cookieWithProperties:properties.get()]; finished = false; clearCookies([WKWebsiteDataStore defaultDataStore]); [httpCookieStore.get() setCookie:sessionCookie.get() completionHandler:^{ finished = true; }]; TestWebKitAPI::Util::run(&finished); finished = false; [httpCookieStore.get() setCookie:sessionCookieDifferentDomain.get() completionHandler:^{ finished = true; }]; TestWebKitAPI::Util::run(&finished); finished = false; [httpCookieStore.get() setCookie:sessionCookieDifferentValue.get() completionHandler:^{ finished = true; }]; TestWebKitAPI::Util::run(&finished); finished = false; [httpCookieStore.get() getAllCookies:^(NSArray *cookies) { EXPECT_EQ(2u, cookies.count); bool sessionCookieExists = false, otherSessionCookieExists = false; for (NSHTTPCookie* cookie in cookies) { if (areCookiesEqual(cookie, sessionCookie.get())) sessionCookieExists = true; else if (areCookiesEqual(cookie, sessionCookieDifferentValue.get())) otherSessionCookieExists = true; } EXPECT_TRUE(sessionCookieExists && otherSessionCookieExists); finished = true; }]; TestWebKitAPI::Util::run(&finished); } TEST(WKHTTPCookieStore, CookiesForURL) { WKHTTPCookieStore *cookieStore = [WKWebsiteDataStore defaultDataStore].httpCookieStore; NSHTTPCookie *webKitCookie = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"webKitName", NSHTTPCookieValue: @"webKitValue", NSHTTPCookieDomain: @"webkit.org", }]; NSHTTPCookie *albuquerque = [NSHTTPCookie cookieWithProperties:@{ NSHTTPCookiePath: @"/", NSHTTPCookieName: @"appleName", NSHTTPCookieValue: @"appleValue", NSHTTPCookieDomain: @"apple.org", }]; __block bool done = false; auto webView = adoptNS([TestWKWebView new]); [webView synchronouslyLoadHTMLString:@"start network process"]; [cookieStore setCookie:webKitCookie completionHandler:^{ [cookieStore setCookie:albuquerque completionHandler:^{ [cookieStore _getCookiesForURL:[NSURL URLWithString:@"https://webkit.org/"] completionHandler:^(NSArray *cookies) { EXPECT_EQ(cookies.count, 1ull); EXPECT_WK_STREQ(cookies[0].name, "webKitName"); [cookieStore deleteCookie:webKitCookie completionHandler:^{ [cookieStore deleteCookie:albuquerque completionHandler:^{ done = true; }]; }]; }]; }]; }]; TestWebKitAPI::Util::run(&done); }