blob: 90caf51d1287a34cbd23d7c15419de980519a246 [file] [log] [blame]
/*
* 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 <WebKit/WKFoundation.h>
#import <WebKit/WKHTTPCookieStorePrivate.h>
#import <WebKit/WKProcessPoolPrivate.h>
#import <WebKit/WKWebsiteDataStorePrivate.h>
#import <WebKit/_WKProcessPoolConfiguration.h>
#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
#import <wtf/BlockPtr.h>
#import <wtf/ProcessPrivilege.h>
#import <wtf/RetainPtr.h>
#import <wtf/Seconds.h>
#import <wtf/text/WTFString.h>
static bool gotFlag;
static uint64_t observerCallbacks;
static RetainPtr<WKHTTPCookieStore> globalCookieStore;
@interface CookieObserver : NSObject<WKHTTPCookieStoreObserver>
- (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<size_t>(0));
globalCookieStore = dataStore.httpCookieStore;
RetainPtr<CookieObserver> observer1 = adoptNS([[CookieObserver alloc] init]);
RetainPtr<CookieObserver> observer2 = adoptNS([[CookieObserver alloc] init]);
[globalCookieStore addObserver:observer1.get()];
[globalCookieStore addObserver:observer2.get()];
RetainPtr<NSArray<NSHTTPCookie *>> cookies;
[globalCookieStore getAllCookies:[&](NSArray<NSHTTPCookie *> *nsCookies) {
cookies = nsCookies;
gotFlag = true;
}];
TestWebKitAPI::Util::run(&gotFlag);
ASSERT_EQ([cookies count], 0u);
gotFlag = false;
RetainPtr<NSHTTPCookie> cookie1 = [NSHTTPCookie cookieWithProperties:@{
NSHTTPCookiePath: @"/",
NSHTTPCookieName: @"CookieName",
NSHTTPCookieValue: @"CookieValue",
NSHTTPCookieDomain: @".www.webkit.org",
NSHTTPCookieSecure: @"TRUE",
NSHTTPCookieDiscard: @"TRUE",
NSHTTPCookieMaximumAge: @"10000",
}];
RetainPtr<NSHTTPCookie> 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<NSHTTPCookie *> *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<NSHTTPCookie *> *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<NSHTTPCookie> 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<NSHTTPCookie *>*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<NSArray<NSHTTPCookie *>> cookies;
[globalCookieStore getAllCookies:[&](NSArray<NSHTTPCookie *> *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<NSHTTPCookie> httpOnlyCookie = [NSHTTPCookie cookieWithProperties:cookieProperties.get()];
[cookieProperties setObject:@"cookieValue2" forKey:NSHTTPCookieValue];
RetainPtr<NSHTTPCookie> httpOnlyCookie2 = [NSHTTPCookie cookieWithProperties:cookieProperties.get()];
[cookieProperties removeObjectForKey:@"HttpOnly"];
RetainPtr<NSHTTPCookie> 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<NSHTTPCookie *> *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<NSHTTPCookie *> *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<NSHTTPCookie *> *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<NSHTTPCookie *> *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<NSNumber> creationTime = @(100000);
[cookieProperties setObject:creationTime.get() forKey:@"Created"];
RetainPtr<NSHTTPCookie> cookie = [NSHTTPCookie cookieWithProperties:cookieProperties.get()];
[globalCookieStore setCookie:cookie.get() completionHandler:[]() {
gotFlag = true;
}];
TestWebKitAPI::Util::run(&gotFlag);
gotFlag = false;
[globalCookieStore getAllCookies:[&](NSArray<NSHTTPCookie *> *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<NSHTTPCookie *> *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 <rdar://problem/35344202> is resolved and bots are updated.
#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED <= 101301
TEST(WKHTTPCookieStore, NonPersistent)
{
RetainPtr<WKWebsiteDataStore> 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<WKWebsiteDataStore> 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<CookieObserver> observer = adoptNS([[CookieObserver alloc] init]);
[globalCookieStore addObserver:observer.get()];
[globalCookieStore getAllCookies:[](NSArray<NSHTTPCookie *> *) {
gotFlag = true;
}];
TestWebKitAPI::Util::run(&gotFlag);
}
static void deleteCookies(WKHTTPCookieStore *store, RetainPtr<NSMutableArray> cookies, BlockPtr<void(void)> completionBlock)
{
if (![cookies count])
return completionBlock();
[store deleteCookie:[cookies lastObject] completionHandler:^(void) {
[cookies removeLastObject];
deleteCookies(store, cookies, completionBlock);
}];
}
TEST(WKHTTPCookieStore, ObserveCookiesReceivedFromHTTP)
{
TestWebKitAPI::HTTPServer server({{ "/", {{{ "Set-Cookie", "testkey=testvalue" }}, "hello" }}});
auto removeAllCookies = [] (WKHTTPCookieStore *store) {
__block bool deletedAllCookies = false;
[store getAllCookies:^(NSArray<NSHTTPCookie *> *cookies) {
deleteCookies(store, adoptNS([cookies mutableCopy]), ^{
deletedAllCookies = true;
});
}];
TestWebKitAPI::Util::run(&deletedAllCookies);
};
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;
removeAllCookies(globalCookieStore.get());
[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<NSHTTPCookie *> *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 <WKUIDelegate>
@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<NSHTTPCookie> sessionCookie = [NSHTTPCookie cookieWithProperties:@{
NSHTTPCookiePath: @"/",
NSHTTPCookieName: @"SessionCookieName",
NSHTTPCookieValue: @"CookieValue",
NSHTTPCookieDomain: @"127.0.0.1",
}];
RetainPtr<NSHTTPCookie> persistentCookie = [NSHTTPCookie cookieWithProperties:@{
NSHTTPCookiePath: @"/",
NSHTTPCookieName: @"PersistentCookieName",
NSHTTPCookieValue: @"CookieValue",
NSHTTPCookieDomain: @"127.0.0.1",
NSHTTPCookieExpires: [NSDate distantFuture],
}];
NSString *alertCookieHTML = @"<script>var cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i ++) { cookies[i] = cookies[i].trim(); } cookies.sort(); alert(cookies.join('; '));</script>";
// NonPersistentDataStore
RetainPtr<WKWebsiteDataStore> ephemeralStoreWithCookies = [WKWebsiteDataStore nonPersistentDataStore];
finished = false;
[ephemeralStoreWithCookies.get().httpCookieStore setCookie:persistentCookie.get() completionHandler:^{
WKWebsiteDataStore *ephemeralStoreWithIndependentCookieStorage = [WKWebsiteDataStore nonPersistentDataStore];
[ephemeralStoreWithIndependentCookieStorage.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *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<NSHTTPCookie *> *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<NSHTTPCookie *> *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<NSHTTPCookie *> *cookies) {
ASSERT_EQ(1u, cookies.count);
finished = true;
}];
}];
TestWebKitAPI::Util::run(&finished);
finished = false;
[defaultStore.httpCookieStore setCookie:sessionCookie.get() completionHandler:^{
[defaultStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *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 <WKUIDelegate>
- (NSString *)alertCookieHTML;
- (NSString *)waitForMessage;
@end
@implementation CheckSessionCookieUIDelegate {
RetainPtr<NSString> _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 @"<script>var cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i ++) { cookies[i] = cookies[i].trim(); } cookies.sort(); alert(cookies.join('; '));</script>";
}
@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<WKWebsiteDataStore> 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<NSHTTPCookie> 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];
}
static void clearCookies(WKHTTPCookieStore* cookieStore)
{
finished = false;
[cookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *cookies) {
if (!cookies || !cookies.count) {
finished = true;
return;
}
unsigned cookiesCount = cookies.count;
__block unsigned deletedCount = 0;
for (NSHTTPCookie* cookie in cookies) {
[cookieStore deleteCookie:cookie completionHandler:^{
if (++deletedCount == cookiesCount)
finished = true;
}];
}
}];
TestWebKitAPI::Util::run(&finished);
}
TEST(WKHTTPCookieStore, WithoutProcessPoolDuplicates)
{
RetainPtr<WKHTTPCookieStore> httpCookieStore = [WKWebsiteDataStore defaultDataStore].httpCookieStore;
RetainPtr<NSHTTPCookie> 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<NSHTTPCookie> sessionCookieDifferentDomain = [NSHTTPCookie cookieWithProperties:properties.get()];
properties.get()[NSHTTPCookieValue] = @"OtherCookieValue";
RetainPtr<NSHTTPCookie> sessionCookieDifferentValue = [NSHTTPCookie cookieWithProperties:properties.get()];
finished = false;
clearCookies(httpCookieStore.get());
[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<NSHTTPCookie *> *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<NSHTTPCookie *> *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);
}