Changeset 256820 in webkit


Ignore:
Timestamp:
Feb 17, 2020, 10:32:42 PM (5 years ago)
Author:
Chris Dumez
Message:

[WK2][Cocoa] Implement in-WebProcess cookie cache to avoid sync IPC for document.cookie in most cases
https://bugs.webkit.org/show_bug.cgi?id=207593
<rdar://problem/56027027>

Reviewed by Antti Koivisto.

Source/WebCore:

Implement in-WebProcess DOM cookie cache for serving document.cookie requests from JavaScript.

The first time document.cookie is called for a given host, the WebProcess will pull in all the
non-HTTPOnly cookies for that host from the NetworkProcess (still via sync IPC) and store them
in an in-memory cookie store. Later document.cookie calls for this host from this WebProcess
will then leverage the in-memory cookie store and avoid doing a sync IPC to the NetworkProcess
entirely.

To maintain the in-process cookie store up-to-date, the WebProcess subscribe for cookie-change
notifications from the NetworkProcess, only for the hosts it is interested in.

If the page's JavaScript sets a cookie by setting document.cookie, we will not invalidate the
cache for performance reasons. Instead, we set the cookie in our in-memory cookie before
sending the new cookie to the NetworkProcess.

For compatibility reasons, any sync IPC to a given host will currently invalidate the cookie
cache for this host. This is because this synchronous load may cause cookies to get set
synchronously and the page could access document.cookie right after the sync XHR. This behavior
is covered by the following existing test:

  • http/tests/cookies/sync-xhr-set-cookie-invalidates-cache.html

Another limitation of the current implementation of the cookie cache is that it is currently
only leveraged for first party content. This is suboptimal and could be improved in a later
iteration. However, the default behavior in Safari is that third-party iframes do not have
cookie access unless they request it using the storage access API. We also currently have
a limit of 5 hosts with cached cookies per WebProcess.

Tests: http/tests/cookies/document-cookie-after-showModalDialog.html

http/tests/cookies/document-cookie-during-iframe-parsing.html

  • dom/Document.cpp:

(WebCore::Document::didLoadResourceSynchronously):

  • dom/Document.h:
  • dom/ScriptExecutionContext.cpp:

(WebCore::ScriptExecutionContext::didLoadResourceSynchronously):

  • dom/ScriptExecutionContext.h:
  • loader/CookieJar.h:
  • loader/ThreadableLoader.cpp:

(WebCore::ThreadableLoader::loadResourceSynchronously):

  • page/MemoryRelease.cpp:

(WebCore::releaseCriticalMemory):

  • page/Settings.yaml:
  • platform/network/NetworkStorageSession.h:

(WebCore::CookieChangeObserver::~CookieChangeObserver):

  • platform/network/cf/NetworkStorageSessionCFNet.cpp:

(WebCore::NetworkStorageSession::NetworkStorageSession):
(WebCore::NetworkStorageSession::cookieStorage const):

  • platform/network/cocoa/NetworkStorageSessionCocoa.mm:

(WebCore::NetworkStorageSession::~NetworkStorageSession):
(WebCore::NetworkStorageSession::setCookie):
(WebCore::NetworkStorageSession::setCookies):
(WebCore::NetworkStorageSession::deleteCookie):
(WebCore::nsCookiesToCookieVector):
(WebCore::NetworkStorageSession::nsCookieStorage const):
(WebCore::createPrivateStorageSession):
(WebCore::NetworkStorageSession::httpCookies const):
(WebCore::NetworkStorageSession::deleteHTTPCookie const):
(WebCore::NetworkStorageSession::setHTTPCookiesForURL const):
(WebCore::NetworkStorageSession::httpCookiesForURL const):
(WebCore::filterCookies):
(WebCore::NetworkStorageSession::cookiesForURL const):
(WebCore::NetworkStorageSession::cookiesForSession const):
(WebCore::NetworkStorageSession::cookiesForDOM const):
(WebCore::NetworkStorageSession::cookieRequestHeaderFieldValue const):
(WebCore::NetworkStorageSession::setCookiesFromDOM const):
(WebCore::NetworkStorageSession::getRawCookies const):
(WebCore::NetworkStorageSession::deleteCookiesForHostnames):
(WebCore::NetworkStorageSession::registerCookieChangeListenersIfNecessary):
(WebCore::NetworkStorageSession::unregisterCookieChangeListenersIfNecessary):
(WebCore::NetworkStorageSession::startListeningForCookieChangeNotifications):
(WebCore::NetworkStorageSession::stopListeningForCookieChangeNotifications):
(WebCore::NetworkStorageSession::domCookiesForHost):
(WebCore::NetworkStorageSession::supportsCookieChangeListenerAPI const):

Source/WebCore/PAL:

Add new CFNetwork SPI to CFNetworkSPI.h for open source builds and for using respondsToSelector.

  • pal/spi/cf/CFNetworkSPI.h:

Source/WebKit:

See WebCore ChangeLog.

  • NetworkProcess/NetworkConnectionToWebProcess.cpp:

(WebKit::NetworkConnectionToWebProcess::~NetworkConnectionToWebProcess):
(WebKit::NetworkConnectionToWebProcess::domCookiesForHost):
(WebKit::NetworkConnectionToWebProcess::unsubscribeFromCookieChangeNotifications):
(WebKit::NetworkConnectionToWebProcess::cookiesAdded):
(WebKit::NetworkConnectionToWebProcess::cookiesDeleted):

  • NetworkProcess/NetworkConnectionToWebProcess.h:
  • NetworkProcess/NetworkConnectionToWebProcess.messages.in:
  • Scripts/webkit/messages.py:
  • Shared/WebPreferences.yaml:
  • Sources.txt:
  • SourcesCocoa.txt:
  • WebKit.xcodeproj/project.pbxproj:
  • WebProcess/Network/NetworkProcessConnection.cpp:

(WebKit::NetworkProcessConnection::cookiesAdded):
(WebKit::NetworkProcessConnection::cookiesDeleted):

  • WebProcess/Network/NetworkProcessConnection.h:
  • WebProcess/Network/NetworkProcessConnection.messages.in:
  • WebProcess/WebPage/Cocoa/WebCookieCacheCocoa.mm: Copied from Source/WebKit/WebProcess/WebPage/WebCookieJar.h.

(WebKit::WebCookieCache::inMemoryStorageSession):

  • WebProcess/WebPage/WebCookieCache.cpp: Added.

(WebKit::WebCookieCache::isFunctional):
(WebKit::WebCookieCache::cookiesForDOM):
(WebKit::WebCookieCache::setCookiesFromDOM):
(WebKit::WebCookieCache::cookiesAdded):
(WebKit::WebCookieCache::cookiesDeleted):
(WebKit::WebCookieCache::clear):
(WebKit::WebCookieCache::clearForHost):
(WebKit::WebCookieCache::pruneCacheIfNecessary):

  • WebProcess/WebPage/WebCookieCache.h: Copied from Source/WebKit/WebProcess/WebPage/WebCookieJar.h.
  • WebProcess/WebPage/WebCookieJar.cpp:

(WebKit::WebCookieJar::isEligibleForCache const):
(WebKit::WebCookieJar::cookies const):
(WebKit::WebCookieJar::setCookies):
(WebKit::WebCookieJar::cookiesAdded):
(WebKit::WebCookieJar::cookiesDeleted):
(WebKit::WebCookieJar::clearCache):
(WebKit::WebCookieJar::clearCacheForHost):

  • WebProcess/WebPage/WebCookieJar.h:
  • WebProcess/WebPage/WebPage.cpp:

(WebKit::m_overriddenMediaType):

  • WebProcess/WebProcess.cpp:

(WebKit::WebProcess::WebProcess):

  • WebProcess/WebProcess.h:

(WebKit::WebProcess::cookieJar):

Source/WTF:

Add build time flags for new feature.

  • wtf/PlatformEnable.h:
  • wtf/PlatformHave.h:

LayoutTests:

Add layout test coverage.

  • http/tests/cookies/document-cookie-after-showModalDialog-expected.txt: Added.
  • http/tests/cookies/document-cookie-after-showModalDialog.html: Added.
  • http/tests/cookies/document-cookie-during-iframe-parsing-expected.txt: Added.
  • http/tests/cookies/document-cookie-during-iframe-parsing.html: Added.
  • http/tests/cookies/resources/close-modal-dialog.html: Added.
  • http/tests/cookies/resources/document-cookie-during-iframe-parsing-iframe.html: Added.
  • http/tests/cookies/resources/set-cookie-and-serve.php: Added.
Location:
trunk
Files:
8 added
38 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r256802 r256820  
     12020-02-17  Chris Dumez  <cdumez@apple.com>
     2
     3        [WK2][Cocoa] Implement in-WebProcess cookie cache to avoid sync IPC for document.cookie in most cases
     4        https://bugs.webkit.org/show_bug.cgi?id=207593
     5        <rdar://problem/56027027>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Add layout test coverage.
     10
     11        * http/tests/cookies/document-cookie-after-showModalDialog-expected.txt: Added.
     12        * http/tests/cookies/document-cookie-after-showModalDialog.html: Added.
     13        * http/tests/cookies/document-cookie-during-iframe-parsing-expected.txt: Added.
     14        * http/tests/cookies/document-cookie-during-iframe-parsing.html: Added.
     15        * http/tests/cookies/resources/close-modal-dialog.html: Added.
     16        * http/tests/cookies/resources/document-cookie-during-iframe-parsing-iframe.html: Added.
     17        * http/tests/cookies/resources/set-cookie-and-serve.php: Added.
     18
    1192020-02-17  Ryan Haddad  <ryanhaddad@apple.com>
    220
  • trunk/Source/WTF/ChangeLog

    r256806 r256820  
     12020-02-17  Chris Dumez  <cdumez@apple.com>
     2
     3        [WK2][Cocoa] Implement in-WebProcess cookie cache to avoid sync IPC for document.cookie in most cases
     4        https://bugs.webkit.org/show_bug.cgi?id=207593
     5        <rdar://problem/56027027>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Add build time flags for new feature.
     10
     11        * wtf/PlatformEnable.h:
     12        * wtf/PlatformHave.h:
     13
    1142020-02-17  Tim Horton  <timothy_horton@apple.com>
    215
  • trunk/Source/WTF/wtf/HashSet.h

    r247767 r256820  
    113113    template<typename IteratorType>
    114114    bool add(IteratorType begin, IteratorType end);
     115    template<typename IteratorType>
     116    bool remove(IteratorType begin, IteratorType end);
    115117
    116118    bool remove(const ValueType&);
     
    272274
    273275template<typename T, typename U, typename V>
     276template<typename IteratorType>
     277inline bool HashSet<T, U, V>::remove(IteratorType begin, IteratorType end)
     278{
     279    bool changed = false;
     280    for (IteratorType iter = begin; iter != end; ++iter)
     281        changed |= remove(*iter);
     282    return changed;
     283}
     284
     285template<typename T, typename U, typename V>
    274286inline bool HashSet<T, U, V>::remove(iterator it)
    275287{
  • trunk/Source/WTF/wtf/PlatformHave.h

    r256806 r256820  
    562562#endif
    563563
     564#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101600) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 140000)
     565#define HAVE_COOKIE_CHANGE_LISTENER_API 1
     566#endif
     567
    564568#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || PLATFORM(IOS_FAMILY)
    565569#define HAVE_DATA_PROTECTION_KEYCHAIN 1
  • trunk/Source/WebCore/ChangeLog

    r256808 r256820  
     12020-02-17  Chris Dumez  <cdumez@apple.com>
     2
     3        [WK2][Cocoa] Implement in-WebProcess cookie cache to avoid sync IPC for document.cookie in most cases
     4        https://bugs.webkit.org/show_bug.cgi?id=207593
     5        <rdar://problem/56027027>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Implement in-WebProcess DOM cookie cache for serving `document.cookie` requests from JavaScript.
     10
     11        The first time document.cookie is called for a given host, the WebProcess will pull in all the
     12        non-HTTPOnly cookies for that host from the NetworkProcess (still via sync IPC) and store them
     13        in an in-memory cookie store. Later document.cookie calls for this host from this WebProcess
     14        will then leverage the in-memory cookie store and avoid doing a sync IPC to the NetworkProcess
     15        entirely.
     16
     17        To maintain the in-process cookie store up-to-date, the WebProcess subscribe for cookie-change
     18        notifications from the NetworkProcess, only for the hosts it is interested in.
     19
     20        If the page's JavaScript sets a cookie by setting document.cookie, we will not invalidate the
     21        cache for performance reasons. Instead, we set the cookie in our in-memory cookie before
     22        sending the new cookie to the NetworkProcess.
     23
     24        For compatibility reasons, any sync IPC to a given host will currently invalidate the cookie
     25        cache for this host. This is because this synchronous load may cause cookies to get set
     26        synchronously and the page could access document.cookie right after the sync XHR. This behavior
     27        is covered by the following existing test:
     28        - http/tests/cookies/sync-xhr-set-cookie-invalidates-cache.html
     29
     30        Another limitation of the current implementation of the cookie cache is that it is currently
     31        only leveraged for first party content. This is suboptimal and could be improved in a later
     32        iteration. However, the default behavior in Safari is that third-party iframes do not have
     33        cookie access unless they request it using the storage access API. We also currently have
     34        a limit of 5 hosts with cached cookies per WebProcess.
     35
     36        Tests: http/tests/cookies/document-cookie-after-showModalDialog.html
     37               http/tests/cookies/document-cookie-during-iframe-parsing.html
     38
     39        * dom/Document.cpp:
     40        (WebCore::Document::didLoadResourceSynchronously):
     41        * dom/Document.h:
     42        * dom/ScriptExecutionContext.cpp:
     43        (WebCore::ScriptExecutionContext::didLoadResourceSynchronously):
     44        * dom/ScriptExecutionContext.h:
     45        * loader/CookieJar.h:
     46        * loader/ThreadableLoader.cpp:
     47        (WebCore::ThreadableLoader::loadResourceSynchronously):
     48        * page/MemoryRelease.cpp:
     49        (WebCore::releaseCriticalMemory):
     50        * page/Settings.yaml:
     51        * platform/network/NetworkStorageSession.h:
     52        (WebCore::CookieChangeObserver::~CookieChangeObserver):
     53        * platform/network/cf/NetworkStorageSessionCFNet.cpp:
     54        (WebCore::NetworkStorageSession::NetworkStorageSession):
     55        (WebCore::NetworkStorageSession::cookieStorage const):
     56        * platform/network/cocoa/NetworkStorageSessionCocoa.mm:
     57        (WebCore::NetworkStorageSession::~NetworkStorageSession):
     58        (WebCore::NetworkStorageSession::setCookie):
     59        (WebCore::NetworkStorageSession::setCookies):
     60        (WebCore::NetworkStorageSession::deleteCookie):
     61        (WebCore::nsCookiesToCookieVector):
     62        (WebCore::NetworkStorageSession::nsCookieStorage const):
     63        (WebCore::createPrivateStorageSession):
     64        (WebCore::NetworkStorageSession::httpCookies const):
     65        (WebCore::NetworkStorageSession::deleteHTTPCookie const):
     66        (WebCore::NetworkStorageSession::setHTTPCookiesForURL const):
     67        (WebCore::NetworkStorageSession::httpCookiesForURL const):
     68        (WebCore::filterCookies):
     69        (WebCore::NetworkStorageSession::cookiesForURL const):
     70        (WebCore::NetworkStorageSession::cookiesForSession const):
     71        (WebCore::NetworkStorageSession::cookiesForDOM const):
     72        (WebCore::NetworkStorageSession::cookieRequestHeaderFieldValue const):
     73        (WebCore::NetworkStorageSession::setCookiesFromDOM const):
     74        (WebCore::NetworkStorageSession::getRawCookies const):
     75        (WebCore::NetworkStorageSession::deleteCookiesForHostnames):
     76        (WebCore::NetworkStorageSession::registerCookieChangeListenersIfNecessary):
     77        (WebCore::NetworkStorageSession::unregisterCookieChangeListenersIfNecessary):
     78        (WebCore::NetworkStorageSession::startListeningForCookieChangeNotifications):
     79        (WebCore::NetworkStorageSession::stopListeningForCookieChangeNotifications):
     80        (WebCore::NetworkStorageSession::domCookiesForHost):
     81        (WebCore::NetworkStorageSession::supportsCookieChangeListenerAPI const):
     82
    1832020-02-17  Chris Dumez  <cdumez@apple.com>
    284
  • trunk/Source/WebCore/PAL/ChangeLog

    r256770 r256820  
     12020-02-17  Chris Dumez  <cdumez@apple.com>
     2
     3        [WK2][Cocoa] Implement in-WebProcess cookie cache to avoid sync IPC for document.cookie in most cases
     4        https://bugs.webkit.org/show_bug.cgi?id=207593
     5        <rdar://problem/56027027>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Add new CFNetwork SPI to CFNetworkSPI.h for open source builds and for using respondsToSelector.
     10
     11        * pal/spi/cf/CFNetworkSPI.h:
     12
    1132020-02-17  Peng Liu  <peng.liu6@apple.com>
    214
  • trunk/Source/WebCore/PAL/pal/spi/cf/CFNetworkSPI.h

    r255461 r256820  
    392392@interface NSHTTPCookieStorage ()
    393393+ (void)_setSharedHTTPCookieStorage:(NSHTTPCookieStorage *)storage;
     394- (void)_setSubscribedDomainsForCookieChanges:(NSSet<NSString*>* __nullable)domainList;
     395- (void)_setCookiesAddedHandler:(void(^__nullable)(NSArray<NSHTTPCookie*>* addedCookies, NSURL* __nullable urlForAddedCookies))cookiesAddedHandler onQueue:(dispatch_queue_t __nullable)queue;
     396- (void)_setCookiesDeletedHandler:(void(^__nullable)(NSArray<NSHTTPCookie*>* __nullable deletedCookies, bool deletedAllCookies))cookiesDeletedHandler onQueue:(dispatch_queue_t __nullable)queue;
     397- (NSArray* __nullable)_getCookiesForDomain:(NSString*)domain;
    394398@end
    395399
  • trunk/Source/WebCore/dom/Document.cpp

    r256786 r256820  
    72047204}
    72057205
    7206 void Document::didLoadResourceSynchronously()
     7206void Document::didLoadResourceSynchronously(const URL& url)
    72077207{
    72087208    // Synchronous resources loading can set cookies so we invalidate the cookies cache
    72097209    // in this case, to be safe.
    72107210    invalidateDOMCookieCache();
     7211
     7212    if (auto* page = this->page())
     7213        page->cookieJar().clearCacheForHost(url.host().toString());
    72117214}
    72127215
  • trunk/Source/WebCore/dom/Document.h

    r256786 r256820  
    16421642    bool isDOMCookieCacheValid() const { return m_cookieCacheExpiryTimer.isActive(); }
    16431643    void invalidateDOMCookieCache();
    1644     void didLoadResourceSynchronously() final;
     1644    void didLoadResourceSynchronously(const URL&) final;
    16451645
    16461646    bool canNavigateInternal(Frame& targetFrame);
  • trunk/Source/WebCore/dom/ScriptExecutionContext.cpp

    r254087 r256820  
    219219}
    220220
    221 void ScriptExecutionContext::didLoadResourceSynchronously()
     221void ScriptExecutionContext::didLoadResourceSynchronously(const URL&)
    222222{
    223223}
  • trunk/Source/WebCore/dom/ScriptExecutionContext.h

    r256012 r256820  
    153153    void destroyedMessagePort(MessagePort&);
    154154
    155     virtual void didLoadResourceSynchronously();
     155    virtual void didLoadResourceSynchronously(const URL&);
    156156
    157157    void ref() { refScriptExecutionContext(); }
  • trunk/Source/WebCore/loader/CookieJar.h

    r250287 r256820  
    6161    virtual void deleteCookie(const Document&, const URL&, const String& cookieName);
    6262
     63    // Cookie Cache.
     64    virtual void clearCache() { }
     65    virtual void clearCacheForHost(const String&) { }
     66
    6367    virtual ~CookieJar();
    6468protected:
  • trunk/Source/WebCore/loader/ThreadableLoader.cpp

    r238933 r256820  
    111111void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext& context, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
    112112{
     113    auto resourceURL = request.url();
    113114    if (is<WorkerGlobalScope>(context))
    114115        WorkerThreadableLoader::loadResourceSynchronously(downcast<WorkerGlobalScope>(context), WTFMove(request), client, options);
    115116    else
    116117        DocumentThreadableLoader::loadResourceSynchronously(downcast<Document>(context), WTFMove(request), client, options);
    117     context.didLoadResourceSynchronously();
     118    context.didLoadResourceSynchronously(resourceURL);
    118119}
    119120
  • trunk/Source/WebCore/page/MemoryRelease.cpp

    r255071 r256820  
    3434#include "ChromeClient.h"
    3535#include "CommonVM.h"
     36#include "CookieJar.h"
    3637#include "Document.h"
    3738#include "FontCache.h"
     
    100101    CSSValuePool::singleton().drain();
    101102
     103    Page::forEachPage([](auto& page) {
     104        page.cookieJar().clearCache();
     105    });
     106
    102107    for (auto& document : copyToVectorOf<RefPtr<Document>>(Document::allDocuments())) {
    103108        document->styleScope().releaseMemory();
  • trunk/Source/WebCore/page/Settings.yaml

    r256808 r256820  
    362362  initial: false
    363363
     364inProcessCookieCacheEnabled:
     365  initial: false
     366
    364367thirdPartyIframeRedirectBlockingEnabled:
    365368  initial: true
  • trunk/Source/WebCore/platform/network/NetworkStorageSession.cpp

    r254931 r256820  
    2727#include "NetworkStorageSession.h"
    2828
     29#include "Cookie.h"
    2930#include "HTTPCookieAcceptPolicy.h"
    3031#include "RuntimeApplicationChecks.h"
     
    5657        removeProcessPrivilege(ProcessPrivilege::CanAccessRawCookies);
    5758}
     59
     60#if !PLATFORM(COCOA)
     61Vector<Cookie> NetworkStorageSession::domCookiesForHost(const String&)
     62{
     63    ASSERT_NOT_IMPLEMENTED_YET();
     64    return { };
     65}
     66#endif // !PLATFORM(COCOA)
    5867
    5968#if ENABLE(RESOURCE_LOAD_STATISTICS)
  • trunk/Source/WebCore/platform/network/NetworkStorageSession.h

    r254931 r256820  
    11/*
    2  * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    6161#if PLATFORM(COCOA)
    6262#include "CookieStorageObserver.h"
     63OBJC_CLASS NSArray;
     64OBJC_CLASS NSHTTPCookie;
     65OBJC_CLASS NSMutableSet;
    6366#endif
    6467
     
    8083enum class ShouldAskITP : bool { No, Yes };
    8184
     85#if HAVE(COOKIE_CHANGE_LISTENER_API)
     86class CookieChangeObserver {
     87public:
     88    virtual ~CookieChangeObserver() { }
     89    virtual void cookiesAdded(const String& host, const Vector<WebCore::Cookie>&) = 0;
     90    virtual void cookiesDeleted() = 0;
     91};
     92#endif
     93
    8294class NetworkStorageSession {
    8395    WTF_MAKE_NONCOPYABLE(NetworkStorageSession); WTF_MAKE_FAST_ALLOCATED;
     
    93105#endif
    94106
     107#if PLATFORM(COCOA)
     108    WEBCORE_EXPORT ~NetworkStorageSession();
     109#endif
     110
    95111#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
    96112    WEBCORE_EXPORT static RetainPtr<CFURLStorageSessionRef> createCFStorageSessionForIdentifier(CFStringRef identifier);
    97     WEBCORE_EXPORT NetworkStorageSession(PAL::SessionID, RetainPtr<CFURLStorageSessionRef>&&, RetainPtr<CFHTTPCookieStorageRef>&&);
     113    enum class IsInMemoryCookieStore : bool { No, Yes };
     114    WEBCORE_EXPORT NetworkStorageSession(PAL::SessionID, RetainPtr<CFURLStorageSessionRef>&&, RetainPtr<CFHTTPCookieStorageRef>&&, IsInMemoryCookieStore = IsInMemoryCookieStore::No);
    98115    WEBCORE_EXPORT explicit NetworkStorageSession(PAL::SessionID);
    99116
     
    146163    WEBCORE_EXPORT std::pair<String, bool> cookieRequestHeaderFieldValue(const URL& firstParty, const SameSiteInfo&, const URL&, Optional<FrameIdentifier>, Optional<PageIdentifier>, IncludeSecureCookies, ShouldAskITP) const;
    147164    WEBCORE_EXPORT std::pair<String, bool> cookieRequestHeaderFieldValue(const CookieRequestHeaderFieldProxy&) const;
     165
     166    WEBCORE_EXPORT Vector<Cookie> domCookiesForHost(const String& host);
     167
     168#if HAVE(COOKIE_CHANGE_LISTENER_API)
     169    WEBCORE_EXPORT void startListeningForCookieChangeNotifications(CookieChangeObserver&, const String& host);
     170    WEBCORE_EXPORT void stopListeningForCookieChangeNotifications(CookieChangeObserver&, const HashSet<String>& hosts);
     171    WEBCORE_EXPORT bool supportsCookieChangeListenerAPI() const;
     172#endif
    148173
    149174#if ENABLE(RESOURCE_LOAD_STATISTICS)
     
    174199
    175200private:
     201#if PLATFORM(COCOA)
     202    enum IncludeHTTPOnlyOrNot { DoNotIncludeHTTPOnly, IncludeHTTPOnly };
     203    std::pair<String, bool> cookiesForSession(const URL& firstParty, const SameSiteInfo&, const URL&, Optional<FrameIdentifier>, Optional<PageIdentifier>, IncludeHTTPOnlyOrNot, IncludeSecureCookies, ShouldAskITP = ShouldAskITP::Yes) const;
     204    NSArray *httpCookies(CFHTTPCookieStorageRef) const;
     205    NSArray *httpCookiesForURL(CFHTTPCookieStorageRef, NSURL *firstParty, const Optional<SameSiteInfo>&, NSURL *) const;
     206    NSArray *cookiesForURL(const URL& firstParty, const SameSiteInfo&, const URL&, Optional<FrameIdentifier>, Optional<PageIdentifier>, ShouldAskITP) const;
     207    void setHTTPCookiesForURL(CFHTTPCookieStorageRef, NSArray *cookies, NSURL *, NSURL *mainDocumentURL, const SameSiteInfo&) const;
     208    void deleteHTTPCookie(CFHTTPCookieStorageRef, NSHTTPCookie *) const;
     209#endif
     210
     211#if HAVE(COOKIE_CHANGE_LISTENER_API)
     212    void registerCookieChangeListenersIfNecessary();
     213    void unregisterCookieChangeListenersIfNecessary();
     214#endif
     215
    176216    PAL::SessionID m_sessionID;
    177217
     
    179219    RetainPtr<CFURLStorageSessionRef> m_platformSession;
    180220    RetainPtr<CFHTTPCookieStorageRef> m_platformCookieStorage;
     221    bool m_isInMemoryCookieStore { false };
    181222#elif USE(SOUP)
    182223    static void cookiesDidChange(NetworkStorageSession*);
     
    189230#else
    190231    RefPtr<NetworkingContext> m_context;
     232#endif
     233
     234#if HAVE(COOKIE_CHANGE_LISTENER_API)
     235    bool m_didRegisterCookieListeners { false };
     236    RetainPtr<NSMutableSet> m_subscribedDomainsForCookieChanges;
     237    HashMap<String, HashSet<CookieChangeObserver*>> m_cookieChangeObservers;
    191238#endif
    192239
  • trunk/Source/WebCore/platform/network/cf/NetworkStorageSessionCFNet.cpp

    r240557 r256820  
    7474}
    7575
    76 NetworkStorageSession::NetworkStorageSession(PAL::SessionID sessionID, RetainPtr<CFURLStorageSessionRef>&& platformSession, RetainPtr<CFHTTPCookieStorageRef>&& platformCookieStorage)
     76NetworkStorageSession::NetworkStorageSession(PAL::SessionID sessionID, RetainPtr<CFURLStorageSessionRef>&& platformSession, RetainPtr<CFHTTPCookieStorageRef>&& platformCookieStorage, IsInMemoryCookieStore isInMemoryCookieStore)
    7777    : m_sessionID(sessionID)
    7878    , m_platformSession(WTFMove(platformSession))
     79    , m_isInMemoryCookieStore(isInMemoryCookieStore == IsInMemoryCookieStore::Yes)
    7980{
    80     ASSERT(processMayUseCookieAPI() || !platformCookieStorage);
     81    ASSERT(processMayUseCookieAPI() || !platformCookieStorage || m_isInMemoryCookieStore);
    8182    m_platformCookieStorage = platformCookieStorage ? WTFMove(platformCookieStorage) : cookieStorage();
    8283}
     
    8990RetainPtr<CFHTTPCookieStorageRef> NetworkStorageSession::cookieStorage() const
    9091{
    91     if (!processMayUseCookieAPI())
     92    if (!processMayUseCookieAPI() && !m_isInMemoryCookieStore)
    9293        return nullptr;
    9394
    94     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     95    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    9596
    9697    if (m_platformCookieStorage)
  • trunk/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm

    r255146 r256820  
    11/*
    2  * Copyright (C) 2015-2018 Apple Inc.  All rights reserved.
     2 * Copyright (C) 2015-2020 Apple Inc.  All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4545namespace WebCore {
    4646
     47NetworkStorageSession::~NetworkStorageSession()
     48{
     49#if HAVE(COOKIE_CHANGE_LISTENER_API)
     50    unregisterCookieChangeListenersIfNecessary();
     51#endif
     52}
     53
    4754void NetworkStorageSession::setCookie(const Cookie& cookie)
    4855{
    49     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     56    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    5057
    5158    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     
    5663void NetworkStorageSession::setCookies(const Vector<Cookie>& cookies, const URL& url, const URL& mainDocumentURL)
    5764{
    58     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     65    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    5966
    6067    RetainPtr<NSMutableArray> nsCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:cookies.size()]);
     
    6976void NetworkStorageSession::deleteCookie(const Cookie& cookie)
    7077{
    71     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     78    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    7279    [nsCookieStorage() deleteCookie:(NSHTTPCookie *)cookie];
    7380}
    7481
    75 static Vector<Cookie> nsCookiesToCookieVector(NSArray<NSHTTPCookie *> *nsCookies)
    76 {
    77     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
    78 
     82static Vector<Cookie> nsCookiesToCookieVector(NSArray<NSHTTPCookie *> *nsCookies, const Function<bool(NSHTTPCookie *)>& filter = { })
     83{
    7984    Vector<Cookie> cookies;
    8085    cookies.reserveInitialCapacity(nsCookies.count);
    81     for (NSHTTPCookie *nsCookie in nsCookies)
    82         cookies.uncheckedAppend(nsCookie);
    83 
     86    for (NSHTTPCookie *nsCookie in nsCookies) {
     87        if (!filter || filter(nsCookie))
     88            cookies.uncheckedAppend(nsCookie);
     89    }
    8490    return cookies;
    8591}
     
    119125NSHTTPCookieStorage *NetworkStorageSession::nsCookieStorage() const
    120126{
    121     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     127    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    122128    auto cfCookieStorage = cookieStorage();
    123129    if (!cfCookieStorage || [NSHTTPCookieStorage sharedHTTPCookieStorage]._cookieStorage == cfCookieStorage)
     
    159165    CFURLCacheSetMemoryCapacity(cache.get(), [[NSURLCache sharedURLCache] memoryCapacity]);
    160166
    161     if (!NetworkStorageSession::processMayUseCookieAPI())
    162         return storageSession.leakRef();
    163 
    164     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
    165 
    166167    auto cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
    167168    if (!cookieStorage)
     
    174175}
    175176
    176 static NSArray *httpCookies(CFHTTPCookieStorageRef cookieStorage)
    177 {
    178     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
    179     if (!cookieStorage)
     177NSArray *NetworkStorageSession::httpCookies(CFHTTPCookieStorageRef cookieStorage) const
     178{
     179    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
     180    if (!cookieStorage) {
     181        RELEASE_ASSERT(!m_isInMemoryCookieStore);
    180182        return [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
     183    }
    181184   
    182185    auto cookies = adoptCF(CFHTTPCookieStorageCopyCookies(cookieStorage));
     
    184187}
    185188
    186 static void deleteHTTPCookie(CFHTTPCookieStorageRef cookieStorage, NSHTTPCookie *cookie)
    187 {
    188     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     189void NetworkStorageSession::deleteHTTPCookie(CFHTTPCookieStorageRef cookieStorage, NSHTTPCookie *cookie) const
     190{
     191    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    189192    if (!cookieStorage) {
     193        RELEASE_ASSERT(!m_isInMemoryCookieStore);
    190194        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    191195        return;
     
    227231}
    228232
    229 static void setHTTPCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSArray *cookies, NSURL *url, NSURL *mainDocumentURL, const SameSiteInfo& sameSiteInfo)
    230 {
    231     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     233void NetworkStorageSession::setHTTPCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSArray *cookies, NSURL *url, NSURL *mainDocumentURL, const SameSiteInfo& sameSiteInfo) const
     234{
     235    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    232236    if (!cookieStorage) {
    233237#if !(PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101400) && !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
     
    256260}
    257261
    258 static NSArray *httpCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSURL *firstParty, const Optional<SameSiteInfo>& sameSiteInfo, NSURL *url)
    259 {
    260     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
    261     if (!cookieStorage)
     262NSArray *NetworkStorageSession::httpCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSURL *firstParty, const Optional<SameSiteInfo>& sameSiteInfo, NSURL *url) const
     263{
     264    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
     265    if (!cookieStorage) {
     266        RELEASE_ASSERT(!m_isInMemoryCookieStore);
    262267        cookieStorage = _CFHTTPCookieStorageGetDefault(kCFAllocatorDefault);
     268    }
    263269
    264270    // FIXME: Stop creating a new NSHTTPCookieStorage object each time we want to query the cookie jar.
    265271    // NetworkStorageSession could instead keep a NSHTTPCookieStorage object for us.
    266272    RetainPtr<NSHTTPCookieStorage> nsCookieStorage = adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorage]);
    267     return cookiesForURL(nsCookieStorage.get(), url, firstParty, sameSiteInfo);
     273    return WebCore::cookiesForURL(nsCookieStorage.get(), url, firstParty, sameSiteInfo);
    268274}
    269275
    270276static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies, Optional<Seconds> cappedLifetime)
    271277{
    272     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
    273278    NSUInteger count = [unfilteredCookies count];
    274279    RetainPtr<NSMutableArray> filteredCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:count]);
     
    303308}
    304309
    305 static NSArray *cookiesForURL(const NetworkStorageSession& session, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, ShouldAskITP shouldAskITP)
     310NSArray *NetworkStorageSession::cookiesForURL(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, ShouldAskITP shouldAskITP) const
    306311{
    307312#if ENABLE(RESOURCE_LOAD_STATISTICS)
    308     if (shouldAskITP == ShouldAskITP::Yes && session.shouldBlockCookies(firstParty, url, frameID, pageID))
     313    if (shouldAskITP == ShouldAskITP::Yes && shouldBlockCookies(firstParty, url, frameID, pageID))
    309314        return nil;
    310315#else
     
    313318    UNUSED_PARAM(shouldAskITP);
    314319#endif
    315     return httpCookiesForURL(session.cookieStorage().get(), firstParty, sameSiteInfo, url);
    316 }
    317 
    318 enum IncludeHTTPOnlyOrNot { DoNotIncludeHTTPOnly, IncludeHTTPOnly };
    319 static std::pair<String, bool> cookiesForSession(const NetworkStorageSession& session, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeHTTPOnlyOrNot includeHTTPOnly, IncludeSecureCookies includeSecureCookies, ShouldAskITP shouldAskITP = ShouldAskITP::Yes)
    320 {
    321     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
    322 
    323     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    324 
    325     NSArray *cookies = cookiesForURL(session, firstParty, sameSiteInfo, url, frameID, pageID, shouldAskITP);
     320    return httpCookiesForURL(cookieStorage().get(), firstParty, sameSiteInfo, url);
     321}
     322
     323std::pair<String, bool> NetworkStorageSession::cookiesForSession(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeHTTPOnlyOrNot includeHTTPOnly, IncludeSecureCookies includeSecureCookies, ShouldAskITP shouldAskITP) const
     324{
     325    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
     326
     327    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     328
     329    NSArray *cookies = cookiesForURL(firstParty, sameSiteInfo, url, frameID, pageID, shouldAskITP);
    326330    if (![cookies count])
    327331        return { String(), false }; // Return a null string, not an empty one that StringBuilder would create below.
     
    375379std::pair<String, bool> NetworkStorageSession::cookiesForDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeSecureCookies includeSecureCookies, ShouldAskITP shouldAskITP) const
    376380{
    377     return cookiesForSession(*this, firstParty, sameSiteInfo, url, frameID, pageID, DoNotIncludeHTTPOnly, includeSecureCookies, shouldAskITP);
     381    return cookiesForSession(firstParty, sameSiteInfo, url, frameID, pageID, DoNotIncludeHTTPOnly, includeSecureCookies, shouldAskITP);
    378382}
    379383
    380384std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeSecureCookies includeSecureCookies, ShouldAskITP shouldAskITP) const
    381385{
    382     return cookiesForSession(*this, firstParty, sameSiteInfo, url, frameID, pageID, IncludeHTTPOnly, includeSecureCookies, shouldAskITP);
     386    return cookiesForSession(firstParty, sameSiteInfo, url, frameID, pageID, IncludeHTTPOnly, includeSecureCookies, shouldAskITP);
    383387}
    384388
    385389std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const CookieRequestHeaderFieldProxy& headerFieldProxy) const
    386390{
    387     return cookiesForSession(*this, headerFieldProxy.firstParty, headerFieldProxy.sameSiteInfo, headerFieldProxy.url, headerFieldProxy.frameID, headerFieldProxy.pageID, IncludeHTTPOnly, headerFieldProxy.includeSecureCookies);
     391    return cookiesForSession(headerFieldProxy.firstParty, headerFieldProxy.sameSiteInfo, headerFieldProxy.url, headerFieldProxy.frameID, headerFieldProxy.pageID, IncludeHTTPOnly, headerFieldProxy.includeSecureCookies);
    388392}
    389393
    390394void NetworkStorageSession::setCookiesFromDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, ShouldAskITP shouldAskITP, const String& cookieStr) const
    391395{
    392     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     396    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    393397
    394398    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     
    458462    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    459463
    460     NSArray *cookies = cookiesForURL(*this, firstParty, sameSiteInfo, url, frameID, pageID, shouldAskITP);
     464    NSArray *cookies = cookiesForURL(firstParty, sameSiteInfo, url, frameID, pageID, shouldAskITP);
    461465    NSUInteger count = [cookies count];
    462466    rawCookies.reserveCapacity(count);
     
    519523void NetworkStorageSession::deleteCookiesForHostnames(const Vector<String>& hostnames, IncludeHttpOnlyCookies includeHttpOnlyCookies)
    520524{
    521     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
     525    ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies) || m_isInMemoryCookieStore);
    522526
    523527    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     
    567571}
    568572
     573Vector<Cookie> NetworkStorageSession::domCookiesForHost(const String& host)
     574{
     575    NSArray *nsCookies = [nsCookieStorage() _getCookiesForDomain:(NSString *)host];
     576    return nsCookiesToCookieVector(nsCookies, [](NSHTTPCookie *cookie) { return !cookie.HTTPOnly; });
     577}
     578
     579#if HAVE(COOKIE_CHANGE_LISTENER_API)
     580
     581void NetworkStorageSession::registerCookieChangeListenersIfNecessary()
     582{
     583    if (m_didRegisterCookieListeners)
     584        return;
     585
     586    m_didRegisterCookieListeners = true;
     587    [nsCookieStorage() _setCookiesAddedHandler:^(NSArray<NSHTTPCookie *> * nsCookies, NSURL *urlForAddedCookies) {
     588        Vector<Cookie> cookies = nsCookiesToCookieVector(nsCookies);
     589        auto host = URL(urlForAddedCookies).host().toString();
     590        RELEASE_ASSERT(!host.isNull());
     591        auto it = m_cookieChangeObservers.find(host);
     592        if (it == m_cookieChangeObservers.end())
     593            return;
     594        for (auto* observer : it->value)
     595            observer->cookiesAdded(host, cookies);
     596    } onQueue:dispatch_get_main_queue()];
     597    [nsCookieStorage() _setCookiesDeletedHandler:^(NSArray<NSHTTPCookie *> *, bool /*deletedAllCookies*/) {
     598        for (auto& observers : m_cookieChangeObservers.values()) {
     599            for (auto* observer : observers)
     600                observer->cookiesDeleted();
     601        }
     602    } onQueue:dispatch_get_main_queue()];
     603}
     604
     605void NetworkStorageSession::unregisterCookieChangeListenersIfNecessary()
     606{
     607    if (!m_didRegisterCookieListeners)
     608        return;
     609
     610    [nsCookieStorage() _setCookiesAddedHandler:nil onQueue:nil];
     611    [nsCookieStorage() _setCookiesDeletedHandler:nil onQueue:nil];
     612    [nsCookieStorage() _setSubscribedDomainsForCookieChanges:nil];
     613    m_didRegisterCookieListeners = false;
     614}
     615
     616void NetworkStorageSession::startListeningForCookieChangeNotifications(CookieChangeObserver& observer, const String& host)
     617{
     618    registerCookieChangeListenersIfNecessary();
     619
     620    auto& observers = m_cookieChangeObservers.ensure(host, [] {
     621        return HashSet<CookieChangeObserver*> { };
     622    }).iterator->value;
     623    ASSERT(!observers.contains(&observer));
     624    observers.add(&observer);
     625
     626    if (!m_subscribedDomainsForCookieChanges)
     627        m_subscribedDomainsForCookieChanges = adoptNS([[NSMutableSet alloc] init]);
     628    else if ([m_subscribedDomainsForCookieChanges containsObject:(NSString *)host])
     629        return;
     630
     631    [m_subscribedDomainsForCookieChanges addObject:(NSString *)host];
     632    [nsCookieStorage() _setSubscribedDomainsForCookieChanges:m_subscribedDomainsForCookieChanges.get()];
     633}
     634
     635void NetworkStorageSession::stopListeningForCookieChangeNotifications(CookieChangeObserver& observer, const HashSet<String>& hosts)
     636{
     637    bool subscribedURLsChanged = false;
     638    for (auto& host : hosts) {
     639        auto it = m_cookieChangeObservers.find(host);
     640        ASSERT(it != m_cookieChangeObservers.end());
     641        if (it == m_cookieChangeObservers.end())
     642            continue;
     643
     644        auto& observers = it->value;
     645        ASSERT(observers.contains(&observer));
     646        observers.remove(&observer);
     647        if (observers.isEmpty()) {
     648            m_cookieChangeObservers.remove(it);
     649            ASSERT([m_subscribedDomainsForCookieChanges containsObject:(NSString *)host]);
     650            [m_subscribedDomainsForCookieChanges removeObject:(NSString *)host];
     651            subscribedURLsChanged = true;
     652        }
     653    }
     654    if (subscribedURLsChanged)
     655        [nsCookieStorage() _setSubscribedDomainsForCookieChanges:m_subscribedDomainsForCookieChanges.get()];
     656}
     657
     658// FIXME: This can eventually go away, this is merely to ensure a smooth transition to the new API.
     659bool NetworkStorageSession::supportsCookieChangeListenerAPI() const
     660{
     661    static const bool supportsAPI = [nsCookieStorage() respondsToSelector:@selector(_setSubscribedDomainsForCookieChanges:)];
     662    return supportsAPI;
     663}
     664
     665#endif // HAVE(COOKIE_CHANGE_LISTENER_API)
     666
    569667} // namespace WebCore
  • trunk/Source/WebKit/ChangeLog

    r256808 r256820  
     12020-02-17  Chris Dumez  <cdumez@apple.com>
     2
     3        [WK2][Cocoa] Implement in-WebProcess cookie cache to avoid sync IPC for document.cookie in most cases
     4        https://bugs.webkit.org/show_bug.cgi?id=207593
     5        <rdar://problem/56027027>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        See WebCore ChangeLog.
     10
     11        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
     12        (WebKit::NetworkConnectionToWebProcess::~NetworkConnectionToWebProcess):
     13        (WebKit::NetworkConnectionToWebProcess::domCookiesForHost):
     14        (WebKit::NetworkConnectionToWebProcess::unsubscribeFromCookieChangeNotifications):
     15        (WebKit::NetworkConnectionToWebProcess::cookiesAdded):
     16        (WebKit::NetworkConnectionToWebProcess::cookiesDeleted):
     17        * NetworkProcess/NetworkConnectionToWebProcess.h:
     18        * NetworkProcess/NetworkConnectionToWebProcess.messages.in:
     19        * Scripts/webkit/messages.py:
     20        * Shared/WebPreferences.yaml:
     21        * Sources.txt:
     22        * SourcesCocoa.txt:
     23        * WebKit.xcodeproj/project.pbxproj:
     24        * WebProcess/Network/NetworkProcessConnection.cpp:
     25        (WebKit::NetworkProcessConnection::cookiesAdded):
     26        (WebKit::NetworkProcessConnection::cookiesDeleted):
     27        * WebProcess/Network/NetworkProcessConnection.h:
     28        * WebProcess/Network/NetworkProcessConnection.messages.in:
     29        * WebProcess/WebPage/Cocoa/WebCookieCacheCocoa.mm: Copied from Source/WebKit/WebProcess/WebPage/WebCookieJar.h.
     30        (WebKit::WebCookieCache::inMemoryStorageSession):
     31        * WebProcess/WebPage/WebCookieCache.cpp: Added.
     32        (WebKit::WebCookieCache::isFunctional):
     33        (WebKit::WebCookieCache::cookiesForDOM):
     34        (WebKit::WebCookieCache::setCookiesFromDOM):
     35        (WebKit::WebCookieCache::cookiesAdded):
     36        (WebKit::WebCookieCache::cookiesDeleted):
     37        (WebKit::WebCookieCache::clear):
     38        (WebKit::WebCookieCache::clearForHost):
     39        (WebKit::WebCookieCache::pruneCacheIfNecessary):
     40        * WebProcess/WebPage/WebCookieCache.h: Copied from Source/WebKit/WebProcess/WebPage/WebCookieJar.h.
     41        * WebProcess/WebPage/WebCookieJar.cpp:
     42        (WebKit::WebCookieJar::isEligibleForCache const):
     43        (WebKit::WebCookieJar::cookies const):
     44        (WebKit::WebCookieJar::setCookies):
     45        (WebKit::WebCookieJar::cookiesAdded):
     46        (WebKit::WebCookieJar::cookiesDeleted):
     47        (WebKit::WebCookieJar::clearCache):
     48        (WebKit::WebCookieJar::clearCacheForHost):
     49        * WebProcess/WebPage/WebCookieJar.h:
     50        * WebProcess/WebPage/WebPage.cpp:
     51        (WebKit::m_overriddenMediaType):
     52        * WebProcess/WebProcess.cpp:
     53        (WebKit::WebProcess::WebProcess):
     54        * WebProcess/WebProcess.h:
     55        (WebKit::WebProcess::cookieJar):
     56
    1572020-02-17  Chris Dumez  <cdumez@apple.com>
    258
  • trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp

    r256583 r256820  
    125125        networkProcess().messagePortChannelRegistry().didCloseMessagePort(port);
    126126
     127#if HAVE(COOKIE_CHANGE_LISTENER_API)
     128    if (auto* networkStorageSession = storageSession())
     129        networkStorageSession->stopListeningForCookieChangeNotifications(*this, m_hostsWithCookieListeners);
     130#endif
     131
    127132#if USE(LIBWEBRTC)
    128133    if (m_rtcProvider)
     
    634639}
    635640
     641void NetworkConnectionToWebProcess::domCookiesForHost(const String& host, bool subscribeToCookieChangeNotifications, CompletionHandler<void(const Vector<WebCore::Cookie>&)>&& completionHandler)
     642{
     643    auto* networkStorageSession = storageSession();
     644    if (!networkStorageSession)
     645        return completionHandler({ });
     646
     647#if HAVE(COOKIE_CHANGE_LISTENER_API)
     648    if (subscribeToCookieChangeNotifications) {
     649        ASSERT(!m_hostsWithCookieListeners.contains(host));
     650        m_hostsWithCookieListeners.add(host);
     651        networkStorageSession->startListeningForCookieChangeNotifications(*this, host);
     652    }
     653#else
     654    UNUSED_PARAM(subscribeToCookieChangeNotifications);
     655#endif
     656
     657    completionHandler(networkStorageSession->domCookiesForHost(host));
     658}
     659
     660#if HAVE(COOKIE_CHANGE_LISTENER_API)
     661
     662void NetworkConnectionToWebProcess::unsubscribeFromCookieChangeNotifications(const HashSet<String>& hosts)
     663{
     664    bool removed = m_hostsWithCookieListeners.remove(hosts.begin(), hosts.end());
     665    ASSERT_UNUSED(removed, removed);
     666
     667    if (auto* networkStorageSession = storageSession())
     668        networkStorageSession->stopListeningForCookieChangeNotifications(*this, hosts);
     669}
     670
     671void NetworkConnectionToWebProcess::cookiesAdded(const String& host, const Vector<WebCore::Cookie>& cookies)
     672{
     673    connection().send(Messages::NetworkProcessConnection::CookiesAdded(host, cookies), 0);
     674}
     675
     676void NetworkConnectionToWebProcess::cookiesDeleted()
     677{
     678    connection().send(Messages::NetworkProcessConnection::CookiesDeleted(), 0);
     679}
     680
     681#endif
     682
    636683void NetworkConnectionToWebProcess::registerFileBlobURL(const URL& url, const String& path, SandboxExtension::Handle&& extensionHandle, const String& contentType)
    637684{
  • trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h

    r256583 r256820  
    4343#include <WebCore/MessagePortIdentifier.h>
    4444#include <WebCore/NetworkLoadInformation.h>
     45#include <WebCore/NetworkStorageSession.h>
    4546#include <WebCore/PageIdentifier.h>
    4647#include <WebCore/ProcessIdentifier.h>
     
    8990    , public WebPaymentCoordinatorProxy::Client
    9091#endif
     92#if HAVE(COOKIE_CHANGE_LISTENER_API)
     93    , public WebCore::CookieChangeObserver
     94#endif
    9195    , IPC::Connection::Client {
    9296public:
     
    267271
    268272    uint64_t nextMessageBatchIdentifier(Function<void()>&&);
     273
     274    void domCookiesForHost(const String& host, bool subscribeToCookieChangeNotifications, CompletionHandler<void(const Vector<WebCore::Cookie>&)>&&);
     275
     276#if HAVE(COOKIE_CHANGE_LISTENER_API)
     277    void unsubscribeFromCookieChangeNotifications(const HashSet<String>& hosts);
     278
     279    // WebCore::CookieChangeObserver.
     280    void cookiesAdded(const String& host, const Vector<WebCore::Cookie>&) final;
     281    void cookiesDeleted() final;
     282#endif
    269283
    270284    struct ResourceNetworkActivityTracker {
     
    331345    NetworkMDNSRegister m_mdnsRegister;
    332346#endif
     347#if HAVE(COOKIE_CHANGE_LISTENER_API)
     348    HashSet<String> m_hostsWithCookieListeners;
     349#endif
    333350
    334351    bool m_captureExtraNetworkLoadMetricsEnabled { false };
  • trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in

    r256583 r256820  
    4040    GetRawCookies(URL firstParty, struct WebCore::SameSiteInfo sameSiteInfo, URL url, Optional<WebCore::FrameIdentifier> frameID, Optional<WebCore::PageIdentifier> pageID, enum:bool WebCore::ShouldAskITP shouldAskITP) -> (Vector<WebCore::Cookie> cookies) Synchronous
    4141    DeleteCookie(URL url, String cookieName)
     42    DomCookiesForHost(String host, bool subscribeToCookieChangeNotifications) -> (Vector<WebCore::Cookie> cookies) Synchronous
     43#if HAVE(COOKIE_CHANGE_LISTENER_API)
     44    UnsubscribeFromCookieChangeNotifications(HashSet<String> hosts)
     45#endif
    4246
    4347    RegisterFileBlobURL(URL url, String path, WebKit::SandboxExtension::Handle extensionHandle, String contentType)
  • trunk/Source/WebKit/Scripts/webkit/messages.py

    r256664 r256820  
    626626        'WebCore::MediaEngineSupportParameters': ['<WebCore/MediaPlayer.h>'],
    627627        'WebCore::ISOWebVTTCue': ['<WebCore/ISOVTTCue.h>'],
     628        'struct WebCore::Cookie': ['<WebCore/Cookie.h>'],
    628629        'struct WebCore::ElementContext': ['<WebCore/ElementContext.h>'],
    629630        'struct WebKit::WebUserScriptData': ['"WebUserContentControllerDataTypes.h"'],
  • trunk/Source/WebKit/Shared/WebPreferences.yaml

    r256697 r256820  
    5454   humanReadableName: "Automatic HTTPS upgrade"
    5555   humanReadableDescription: "Automatic HTTPS upgrade for known supported sites"
     56   category: experimental
     57
     58InProcessCookieCacheEnabled:
     59   type: bool
     60   defaultValue: true
     61   humanReadableName: "In-Process Cookie Cache"
     62   humanReadableDescription: "In-Process DOM Cookie Cache"
    5663   category: experimental
    5764
  • trunk/Source/WebKit/Sources.txt

    r256353 r256820  
    625625WebProcess/WebPage/WebBackForwardListProxy.cpp
    626626WebProcess/WebPage/WebContextMenu.cpp
     627WebProcess/WebPage/WebCookieCache.cpp
    627628WebProcess/WebPage/WebCookieJar.cpp
    628629WebProcess/WebPage/WebDocumentLoader.cpp
  • trunk/Source/WebKit/SourcesCocoa.txt

    r255998 r256820  
    614614
    615615WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.mm
     616WebProcess/WebPage/Cocoa/WebCookieCacheCocoa.mm
    616617WebProcess/WebPage/Cocoa/WebPageCocoa.mm
    617618WebProcess/WebPage/Cocoa/WebRemoteObjectRegistry.cpp
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r256756 r256820  
    944944                4671FF1F23217EFF001B64C7 /* WebResourceLoadObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4671FF1D23217EFF001B64C7 /* WebResourceLoadObserver.h */; };
    945945                467E43E82243FF7D00B13924 /* WebProcessDataStoreParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 467E43E72243FF6D00B13924 /* WebProcessDataStoreParameters.h */; };
     946                46809A7C23D9225E00C297D0 /* WebCookieCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 46809A7A23D9225300C297D0 /* WebCookieCache.h */; };
    946947                46A2B6091E5676A600C3DEDA /* BackgroundProcessResponsivenessTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */; };
    947948                46B0524722668D8500265B97 /* WebDeviceOrientationAndMotionAccessController.h in Headers */ = {isa = PBXBuildFile; fileRef = 46B0524422668D2300265B97 /* WebDeviceOrientationAndMotionAccessController.h */; };
     
    34873488                4671FF1E23217EFF001B64C7 /* WebResourceLoadObserver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebResourceLoadObserver.cpp; sourceTree = "<group>"; };
    34883489                467E43E72243FF6D00B13924 /* WebProcessDataStoreParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebProcessDataStoreParameters.h; sourceTree = "<group>"; };
     3490                46809A7A23D9225300C297D0 /* WebCookieCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebCookieCache.h; sourceTree = "<group>"; };
     3491                46809A7B23D9225300C297D0 /* WebCookieCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebCookieCache.cpp; sourceTree = "<group>"; };
    34893492                4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProvisionalPageProxy.h; sourceTree = "<group>"; };
    34903493                4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProvisionalPageProxy.cpp; sourceTree = "<group>"; };
     
    84298432                                51871B59127CB89D00F76232 /* WebContextMenu.cpp */,
    84308433                                51871B5A127CB89D00F76232 /* WebContextMenu.h */,
     8434                                46809A7B23D9225300C297D0 /* WebCookieCache.cpp */,
     8435                                46809A7A23D9225300C297D0 /* WebCookieCache.h */,
    84318436                                5C7FB46E21E97C0B009E3241 /* WebCookieJar.cpp */,
    84328437                                5C7FB46F21E97C0C009E3241 /* WebCookieJar.h */,
     
    1066910674                                51ACBBA0127A8F2C00D203B9 /* WebContextMenuProxyMac.h in Headers */,
    1067010675                                BCF4DE25168FA44800C94AFC /* WebContextSupplement.h in Headers */,
     10676                                46809A7C23D9225E00C297D0 /* WebCookieCache.h in Headers */,
    1067110677                                5C7FB47021E97DC5009E3241 /* WebCookieJar.h in Headers */,
    1067210678                                330934501315B94D0097A7BC /* WebCookieManager.h in Headers */,
  • trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp

    r256303 r256820  
    3333#include "StorageAreaMapMessages.h"
    3434#include "WebCacheStorageProvider.h"
     35#include "WebCookieJar.h"
    3536#include "WebCoreArgumentCoders.h"
    3637#include "WebIDBConnectionToServer.h"
     
    235236}
    236237
     238#if HAVE(COOKIE_CHANGE_LISTENER_API)
     239void NetworkProcessConnection::cookiesAdded(const String& host, const Vector<WebCore::Cookie>& cookies)
     240{
     241    WebProcess::singleton().cookieJar().cookiesAdded(host, cookies);
     242}
     243
     244void NetworkProcessConnection::cookiesDeleted()
     245{
     246    WebProcess::singleton().cookieJar().cookiesDeleted();
     247}
     248#endif
     249
    237250#if ENABLE(SHAREABLE_RESOURCE)
    238251void NetworkProcessConnection::didCacheResource(const ResourceRequest& request, const ShareableResource::Handle& handle)
  • trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.h

    r254931 r256820  
    4242class ResourceRequest;
    4343class ResourceResponse;
     44struct Cookie;
    4445struct MessagePortIdentifier;
    4546struct MessageWithMessagePorts;
     
    8485    bool cookiesEnabled() const;
    8586
     87#if HAVE(COOKIE_CHANGE_LISTENER_API)
     88    void cookiesAdded(const String& host, const Vector<WebCore::Cookie>&);
     89    void cookiesDeleted();
     90#endif
     91
    8692private:
    8793    NetworkProcessConnection(IPC::Connection::Identifier, WebCore::HTTPCookieAcceptPolicy);
  • trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.messages.in

    r254931 r256820  
    3232    CookieAcceptPolicyChanged(enum:uint8_t WebCore::HTTPCookieAcceptPolicy policy);
    3333
     34#if HAVE(COOKIE_CHANGE_LISTENER_API)
     35    CookiesAdded(String host, Vector<struct WebCore::Cookie> cookies);
     36    CookiesDeleted();
     37#endif
     38
    3439    CheckProcessLocalPortForActivity(struct WebCore::MessagePortIdentifier port) -> (WebCore::MessagePortChannelProvider::HasActivity hasActivity) Async
    3540    MessagesAvailableForPort(struct WebCore::MessagePortIdentifier port)
  • trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebCookieCacheCocoa.mm

    r256808 r256820  
    11/*
    2  * Copyright (C) 2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #pragma once
     26#import "config.h"
     27#import "WebCookieCache.h"
    2728
    28 #include <WebCore/CookieJar.h>
     29#import "WebProcess.h"
     30#import <WebCore/NetworkStorageSession.h>
    2931
    3032namespace WebKit {
    3133
    32 class WebCookieJar final : public WebCore::CookieJar {
    33 public:
    34     static Ref<WebCookieJar> create() { return adoptRef(*new WebCookieJar); }
    35    
    36     String cookies(WebCore::Document&, const URL&) const final;
    37     void setCookies(WebCore::Document&, const URL&, const String& cookieString) final;
    38     bool cookiesEnabled(const WebCore::Document&) const final;
    39     std::pair<String, WebCore::SecureCookiesAccessed> cookieRequestHeaderFieldValue(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, Optional<WebCore::FrameIdentifier>, Optional<WebCore::PageIdentifier>, WebCore::IncludeSecureCookies) const final;
    40     bool getRawCookies(const WebCore::Document&, const URL&, Vector<WebCore::Cookie>&) const final;
    41     void deleteCookie(const WebCore::Document&, const URL&, const String& cookieName) final;
    42 private:
    43     WebCookieJar();
    44 };
     34using namespace WebCore;
     35
     36NetworkStorageSession& WebCookieCache::inMemoryStorageSession()
     37{
     38    if (!m_inMemoryStorageSession) {
     39        String sessionName = makeString("WebKitInProcessStorage-", getCurrentProcessID());
     40        auto storageSession = adoptCF(WebCore::createPrivateStorageSession(sessionName.createCFString().get()));
     41        auto cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
     42        m_inMemoryStorageSession = makeUnique<NetworkStorageSession>(WebProcess::singleton().sessionID(), WTFMove(storageSession), WTFMove(cookieStorage), NetworkStorageSession::IsInMemoryCookieStore::Yes);
     43    }
     44    return *m_inMemoryStorageSession;
     45}
    4546
    4647} // namespace WebKit
  • trunk/Source/WebKit/WebProcess/WebPage/WebCookieCache.h

    r256808 r256820  
    11/*
    2  * Copyright (C) 2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2727
    2828#include <WebCore/CookieJar.h>
     29#include <WebCore/SameSiteInfo.h>
     30#include <wtf/HashSet.h>
     31
     32namespace WebCore {
     33class NetworkStorageSession;
     34}
    2935
    3036namespace WebKit {
    3137
    32 class WebCookieJar final : public WebCore::CookieJar {
     38class WebCookieCache {
    3339public:
    34     static Ref<WebCookieJar> create() { return adoptRef(*new WebCookieJar); }
    35    
    36     String cookies(WebCore::Document&, const URL&) const final;
    37     void setCookies(WebCore::Document&, const URL&, const String& cookieString) final;
    38     bool cookiesEnabled(const WebCore::Document&) const final;
    39     std::pair<String, WebCore::SecureCookiesAccessed> cookieRequestHeaderFieldValue(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, Optional<WebCore::FrameIdentifier>, Optional<WebCore::PageIdentifier>, WebCore::IncludeSecureCookies) const final;
    40     bool getRawCookies(const WebCore::Document&, const URL&, Vector<WebCore::Cookie>&) const final;
    41     void deleteCookie(const WebCore::Document&, const URL&, const String& cookieName) final;
     40    WebCookieCache() = default;
     41
     42    bool isSupported();
     43
     44    String cookiesForDOM(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::IncludeSecureCookies);
     45    void setCookiesFromDOM(const URL& firstParty, const WebCore::SameSiteInfo&, const URL&, WebCore::FrameIdentifier, WebCore::PageIdentifier, const String& cookieString);
     46
     47    void cookiesAdded(const String& host, const Vector<WebCore::Cookie>&);
     48    void cookiesDeleted();
     49
     50    void clear();
     51    void clearForHost(const String&);
     52
    4253private:
    43     WebCookieJar();
     54    WebCore::NetworkStorageSession& inMemoryStorageSession();
     55    void pruneCacheIfNecessary();
     56
     57    HashSet<String> m_hostsWithInMemoryStorage;
     58    std::unique_ptr<WebCore::NetworkStorageSession> m_inMemoryStorageSession;
    4459};
    4560
  • trunk/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp

    r254931 r256820  
    11/*
    2  * Copyright (C) 2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838#include <WebCore/FrameLoader.h>
    3939#include <WebCore/FrameLoaderClient.h>
     40#include <WebCore/Settings.h>
    4041#include <WebCore/StorageSessionProvider.h>
    4142
     
    8990#endif
    9091
     92bool WebCookieJar::isEligibleForCache(WebFrame& frame, const URL& firstPartyForCookies, const URL& resourceURL) const
     93{
     94    auto* page = frame.page() ? frame.page()->corePage() : nullptr;
     95    if (!page || !page->settings().inProcessCookieCacheEnabled())
     96        return false;
     97
     98    if (!m_cache.isSupported())
     99        return false;
     100
     101    // For now, we only cache cookies for first-party content. Third-party cookie caching is a bit more complicated due to partitioning and storage access.
     102    RegistrableDomain resourceDomain { resourceURL };
     103    if (resourceDomain.isEmpty())
     104        return false;
     105
     106    return frame.isMainFrame() || RegistrableDomain { firstPartyForCookies } == resourceDomain;
     107}
     108
    91109String WebCookieJar::cookies(WebCore::Document& document, const URL& url) const
    92110{
     
    101119#endif
    102120
     121    auto sameSiteInfo = CookieJar::sameSiteInfo(document);
     122    auto includeSecureCookies = CookieJar::shouldIncludeSecureCookies(document, url);
    103123    auto frameID = webFrame->frameID();
    104124    auto pageID = webFrame->page()->identifier();
    105125
     126    if (isEligibleForCache(*webFrame, document.firstPartyForCookies(), url))
     127        return m_cache.cookiesForDOM(document.firstPartyForCookies(), sameSiteInfo, url, frameID, pageID, includeSecureCookies);
     128
    106129    String cookieString;
    107130    bool secureCookiesAccessed = false;
    108     if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::CookiesForDOM(document.firstPartyForCookies(), sameSiteInfo(document), url, frameID, pageID, shouldIncludeSecureCookies(document, url), shouldAskITPInNetworkProcess), Messages::NetworkConnectionToWebProcess::CookiesForDOM::Reply(cookieString, secureCookiesAccessed), 0))
     131    if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::CookiesForDOM(document.firstPartyForCookies(), sameSiteInfo, url, frameID, pageID, includeSecureCookies, shouldAskITPInNetworkProcess), Messages::NetworkConnectionToWebProcess::CookiesForDOM::Reply(cookieString, secureCookiesAccessed), 0))
    109132        return { };
    110133
     
    124147#endif
    125148
     149    auto sameSiteInfo = CookieJar::sameSiteInfo(document);
    126150    auto frameID = webFrame->frameID();
    127151    auto pageID = webFrame->page()->identifier();
    128152
    129     WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCookiesFromDOM(document.firstPartyForCookies(), sameSiteInfo(document), url, frameID, pageID, shouldAskITPInNetworkProcess, cookieString), 0);
     153    if (isEligibleForCache(*webFrame, document.firstPartyForCookies(), url))
     154        m_cache.setCookiesFromDOM(document.firstPartyForCookies(), sameSiteInfo, url, frameID, pageID, cookieString);
     155
     156    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCookiesFromDOM(document.firstPartyForCookies(), sameSiteInfo, url, frameID, pageID, shouldAskITPInNetworkProcess, cookieString), 0);
     157}
     158
     159void WebCookieJar::cookiesAdded(const String& host, const Vector<WebCore::Cookie>& cookies)
     160{
     161    m_cache.cookiesAdded(host, cookies);
     162}
     163
     164void WebCookieJar::cookiesDeleted()
     165{
     166    m_cache.cookiesDeleted();
     167}
     168
     169void WebCookieJar::clearCache()
     170{
     171    m_cache.clear();
     172}
     173
     174void WebCookieJar::clearCacheForHost(const String& host)
     175{
     176    m_cache.clearForHost(host);
    130177}
    131178
  • trunk/Source/WebKit/WebProcess/WebPage/WebCookieJar.h

    r250153 r256820  
    11/*
    2  * Copyright (C) 2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2626#pragma once
    2727
     28#include "WebCookieCache.h"
    2829#include <WebCore/CookieJar.h>
    2930
     31namespace WebCore {
     32struct Cookie;
     33}
     34
    3035namespace WebKit {
     36
     37class WebFrame;
    3138
    3239class WebCookieJar final : public WebCore::CookieJar {
     
    4047    bool getRawCookies(const WebCore::Document&, const URL&, Vector<WebCore::Cookie>&) const final;
    4148    void deleteCookie(const WebCore::Document&, const URL&, const String& cookieName) final;
     49
     50    void cookiesAdded(const String& host, const Vector<WebCore::Cookie>&);
     51    void cookiesDeleted();
     52
    4253private:
    4354    WebCookieJar();
     55
     56    void clearCache() final;
     57    void clearCacheForHost(const String&) final;
     58    bool isEligibleForCache(WebFrame&, const URL& firstPartyForCookies, const URL& resourceURL) const;
     59
     60    mutable WebCookieCache m_cache;
    4461};
    4562
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp

    r256715 r256820  
    467467        WebProcess::singleton().cacheStorageProvider(),
    468468        WebBackForwardListProxy::create(*this),
    469         WebCookieJar::create(),
     469        WebProcess::singleton().cookieJar(),
    470470        makeUniqueRef<WebProgressTrackerClient>(*this),
    471471        makeUniqueRef<MediaRecorderProvider>()
  • trunk/Source/WebKit/WebProcess/WebProcess.cpp

    r256742 r256820  
    4949#include "WebCacheStorageProvider.h"
    5050#include "WebConnectionToUIProcess.h"
     51#include "WebCookieJar.h"
    5152#include "WebCoreArgumentCoders.h"
    5253#include "WebFrame.h"
     
    206207    , m_webLoaderStrategy(*new WebLoaderStrategy)
    207208    , m_cacheStorageProvider(WebCacheStorageProvider::create())
     209    , m_cookieJar(WebCookieJar::create())
    208210    , m_dnsPrefetchHystereris([this](PAL::HysteresisState state) { if (state == PAL::HysteresisState::Stopped) m_dnsPrefetchedHosts.clear(); })
    209211#if ENABLE(NETSCAPE_PLUGIN_API)
  • trunk/Source/WebKit/WebProcess/WebProcess.h

    r256756 r256820  
    121121class WebAutomationSessionProxy;
    122122class WebCacheStorageProvider;
     123class WebCookieJar;
    123124class WebCompiledContentRuleListData;
    124125class WebConnectionToUIProcess;
     
    294295
    295296    WebCacheStorageProvider& cacheStorageProvider() { return m_cacheStorageProvider.get(); }
     297    WebCookieJar& cookieJar() { return m_cookieJar.get(); }
    296298    WebSocketChannelManager& webSocketChannelManager() { return m_webSocketChannelManager; }
    297299
     
    559561
    560562    Ref<WebCacheStorageProvider> m_cacheStorageProvider;
     563    Ref<WebCookieJar> m_cookieJar;
    561564    WebSocketChannelManager m_webSocketChannelManager;
    562565
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/CookieAcceptPolicy.mm

    r242339 r256820  
    3333#import <pal/spi/cf/CFNetworkSPI.h>
    3434#import <wtf/RetainPtr.h>
     35
     36// FIXME: This test is causing flakiness in API tests. It sets the cookie accept policy to 'Never'
     37// and following tests often are unable to set cookies.
     38#if !PLATFORM(IOS_FAMILY)
    3539
    3640static bool receivedScriptMessage = false;
     
    7377    [[NSHTTPCookieStorage sharedHTTPCookieStorage] _saveCookies];
    7478}
     79
     80#endif // !PLATFORM(IOS_FAMILY)
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/CookiePrivateBrowsing.mm

    r242339 r256820  
    2727
    2828#import "PlatformUtilities.h"
     29#import "Test.h"
     30#import "TestWKWebView.h"
    2931#import <WebKit/WKProcessPool.h>
    3032#import <WebKit/WKProcessPoolPrivate.h>
     
    3234#import <WebKit/WKWebViewConfiguration.h>
    3335#import <wtf/RetainPtr.h>
     36#import <wtf/text/WTFString.h>
    3437
    3538static bool receivedAlert;
     
    6972    TestWebKitAPI::Util::run(&receivedAlert);
    7073}
     74
     75TEST(WebKit, CookieCacheSyncAcrossProcess)
     76{
     77    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     78    [configuration setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]];
     79    auto view1 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
     80    auto view2 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
     81    [view1 synchronouslyLoadHTMLString:@"foo" baseURL:[NSURL URLWithString:@"http://example.com/"]];
     82    [view2 synchronouslyLoadHTMLString:@"bar" baseURL:[NSURL URLWithString:@"http://example.com/"]];
     83
     84    // Cache DOM cookies in first WebView.
     85    __block bool doneEvaluatingJavaScript = false;
     86    [view1 evaluateJavaScript:@"document.cookie;" completionHandler:^(id _Nullable cookie, NSError * _Nullable error) {
     87        EXPECT_NULL(error);
     88        EXPECT_TRUE([cookie isKindOfClass:[NSString class]]);
     89        EXPECT_WK_STREQ("", (NSString *)cookie);
     90        doneEvaluatingJavaScript = true;
     91    }];
     92    TestWebKitAPI::Util::run(&doneEvaluatingJavaScript);
     93
     94    // Cache DOM cookies in second WebView.
     95    doneEvaluatingJavaScript = false;
     96    [view2 evaluateJavaScript:@"document.cookie;" completionHandler:^(id _Nullable cookie, NSError * _Nullable error) {
     97        EXPECT_NULL(error);
     98        EXPECT_TRUE([cookie isKindOfClass:[NSString class]]);
     99        EXPECT_WK_STREQ("", (NSString *)cookie);
     100        doneEvaluatingJavaScript = true;
     101    }];
     102    TestWebKitAPI::Util::run(&doneEvaluatingJavaScript);
     103
     104    // Setting cookie in first Webview / process.
     105    doneEvaluatingJavaScript = false;
     106    [view1 evaluateJavaScript:@"document.cookie = 'foo=bar'; document.cookie;" completionHandler:^(id _Nullable cookie, NSError * _Nullable error) {
     107        EXPECT_NULL(error);
     108        EXPECT_TRUE([cookie isKindOfClass:[NSString class]]);
     109        EXPECT_WK_STREQ("foo=bar", (NSString *)cookie);
     110        doneEvaluatingJavaScript = true;
     111    }];
     112    TestWebKitAPI::Util::run(&doneEvaluatingJavaScript);
     113
     114    // Making sure new cookie gets sync'd to second WebView process.
     115    int timeout = 0;
     116    __block String cookieString;
     117    do {
     118        TestWebKitAPI::Util::sleep(0.1);
     119        doneEvaluatingJavaScript = false;
     120        [view2 evaluateJavaScript:@"document.cookie;" completionHandler:^(id _Nullable cookie, NSError * _Nullable error) {
     121            EXPECT_NULL(error);
     122            EXPECT_TRUE([cookie isKindOfClass:[NSString class]]);
     123            cookieString = (NSString *)cookie;
     124            doneEvaluatingJavaScript = true;
     125        }];
     126        TestWebKitAPI::Util::run(&doneEvaluatingJavaScript);
     127        ++timeout;
     128    } while (cookieString != "" && timeout < 50);
     129    EXPECT_WK_STREQ("foo=bar", cookieString);
     130}
Note: See TracChangeset for help on using the changeset viewer.