Changeset 252185 in webkit


Ignore:
Timestamp:
Nov 7, 2019 9:05:18 AM (5 years ago)
Author:
achristensen@apple.com
Message:

Re-enable NSURLSession isolation after r252116
https://bugs.webkit.org/show_bug.cgi?id=203934
<rdar://problem/56921584>

Reviewed by Chris Dumez.

Source/WebCore:

  • platform/network/StoredCredentialsPolicy.h:

Source/WebKit:

r252116 was a rollout of r248640, which introduced cases where data tasks from different NSURLSessions
which can have the same task identifiers were put into the same maps. This key collision caused data from the wrong
tasks to be sent to NetworkResourceLoader, causing rare and strange loading bugs. In order to prevent insertion into
wrong maps again, I made a new abstraction, SessionWrapper, which wraps a NSURLSession, its delegate, and all maps
that are scoped to that NSURLSession. Along the way I found a few other places where we had made similar mistakes.

Covered by an API test which would've failed before r252116 because it exercises the key collision condition,
and by tests which were skipped in r252116 and I now unskipped.

  • NetworkProcess/Downloads/cocoa/DownloadCocoa.mm:

(WebKit::Download::resume):

  • NetworkProcess/cocoa/NetworkDataTaskCocoa.h:
  • NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:

(WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
(WebKit::NetworkDataTaskCocoa::~NetworkDataTaskCocoa):

  • NetworkProcess/cocoa/NetworkSessionCocoa.h:
  • NetworkProcess/cocoa/NetworkSessionCocoa.mm:

(-[WKNetworkSessionDelegate initWithSessionWrapper:withCredentials:]):
(-[WKNetworkSessionDelegate sessionInvalidated]):
(-[WKNetworkSessionDelegate existingTask:]):
(-[WKNetworkSessionDelegate sessionCocoa]):
(-[WKNetworkSessionDelegate URLSession:didBecomeInvalidWithError:]):
(-[WKNetworkSessionDelegate URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:]):
(-[WKNetworkSessionDelegate URLSession:task:_schemeUpgraded:completionHandler:]):
(-[WKNetworkSessionDelegate URLSession:dataTask:willCacheResponse:completionHandler:]):
(processServerTrustEvaluation):
(-[WKNetworkSessionDelegate URLSession:task:didReceiveChallenge:completionHandler:]):
(-[WKNetworkSessionDelegate URLSession:task:didCompleteWithError:]):
(-[WKNetworkSessionDelegate URLSession:downloadTask:didFinishDownloadingToURL:]):
(-[WKNetworkSessionDelegate URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:]):
(-[WKNetworkSessionDelegate URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:]):
(-[WKNetworkSessionDelegate URLSession:dataTask:didBecomeDownloadTask:]):
(-[WKNetworkSessionDelegate existingWebSocketTask:]):
(WebKit::SessionWrapper::initialize):
(WebKit::NetworkSessionCocoa::NetworkSessionCocoa):
(WebKit::NetworkSessionCocoa::initializeEphemeralStatelessSession):
(WebKit::NetworkSessionCocoa::sessionWrapperForTask):
(WebKit::NetworkSessionCocoa::isolatedSession):
(WebKit::NetworkSessionCocoa::invalidateAndCancel):
(WebKit::NetworkSessionCocoa::continueDidReceiveChallenge):
(WebKit::NetworkSessionCocoa::createWebSocketTask):
(WebKit::NetworkSessionCocoa::addWebSocketTask):
(WebKit::NetworkSessionCocoa::removeWebSocketTask):
(-[WKNetworkSessionDelegate initWithNetworkSession:withCredentials:]): Deleted.
(WebKit::NetworkSessionCocoa::initializeEphemeralStatelessCookielessSession): Deleted.
(WebKit::NetworkSessionCocoa::session): Deleted.
(WebKit::NetworkSessionCocoa::dataTaskForIdentifier): Deleted.
(WebKit::NetworkSessionCocoa::downloadTaskWithResumeData): Deleted.
(WebKit::NetworkSessionCocoa::addDownloadID): Deleted.
(WebKit::NetworkSessionCocoa::downloadID): Deleted.
(WebKit::NetworkSessionCocoa::takeDownloadID): Deleted.
(WebKit::NetworkSessionCocoa::webSocketDataTaskForIdentifier): Deleted.

  • UIProcess/API/Cocoa/WKWebsiteDataStore.mm:

(-[WKWebsiteDataStore _logUserInteraction:completionHandler:]):

  • UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/ResourceLoadStatistics.mm:

(-[DataTaskIdentifierCollisionDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
(-[DataTaskIdentifierCollisionDelegate waitForMessages:]):
(-[DataTaskIdentifierCollisionDelegate webView:didReceiveAuthenticationChallenge:completionHandler:]):
(TEST):

LayoutTests:

  • platform/wk2/TestExpectations:

Re-enable skipped tests.

Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252172 r252185  
     12019-11-07  Alex Christensen  <achristensen@webkit.org>
     2
     3        Re-enable NSURLSession isolation after r252116
     4        https://bugs.webkit.org/show_bug.cgi?id=203934
     5        <rdar://problem/56921584>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * platform/wk2/TestExpectations:
     10        Re-enable skipped tests.
     11
    1122019-11-06  Antti Koivisto  <antti@apple.com>
    213
  • trunk/LayoutTests/platform/wk2/TestExpectations

    r252116 r252185  
    747747http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Skip ]
    748748
    749 # rdar://problem/56921584
    750 http/tests/resourceLoadStatistics/switch-session-on-navigation-to-prevalent-with-interaction.php [ Skip ]
    751 http/tests/resourceLoadStatistics/switch-session-on-navigation-to-prevalent-with-interaction-database.php [ Skip ]
    752 
    753749# This feature is currently disabled by default and unfinished <rdar://problem/38925077>.
    754750http/tests/navigation/process-swap-window-open.html [ Skip ]
  • trunk/Source/WebCore/ChangeLog

    r252182 r252185  
     12019-11-07  Alex Christensen  <achristensen@webkit.org>
     2
     3        Re-enable NSURLSession isolation after r252116
     4        https://bugs.webkit.org/show_bug.cgi?id=203934
     5        <rdar://problem/56921584>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * platform/network/StoredCredentialsPolicy.h:
     10
    1112019-11-07  Andres Gonzalez  <andresg_22@apple.com>
    212
  • trunk/Source/WebCore/platform/network/StoredCredentialsPolicy.h

    r244475 r252185  
    3131    DoNotUse,
    3232    Use,
    33     EphemeralStatelessCookieless
     33    EphemeralStateless
    3434};
    3535
  • trunk/Source/WebKit/ChangeLog

    r252183 r252185  
     12019-11-07  Alex Christensen  <achristensen@webkit.org>
     2
     3        Re-enable NSURLSession isolation after r252116
     4        https://bugs.webkit.org/show_bug.cgi?id=203934
     5        <rdar://problem/56921584>
     6
     7        Reviewed by Chris Dumez.
     8
     9        r252116 was a rollout of r248640, which introduced cases where data tasks from different NSURLSessions
     10        which can have the same task identifiers were put into the same maps.  This key collision caused data from the wrong
     11        tasks to be sent to NetworkResourceLoader, causing rare and strange loading bugs.  In order to prevent insertion into
     12        wrong maps again, I made a new abstraction, SessionWrapper, which wraps a NSURLSession, its delegate, and all maps
     13        that are scoped to that NSURLSession.  Along the way I found a few other places where we had made similar mistakes.
     14
     15        Covered by an API test which would've failed before r252116 because it exercises the key collision condition,
     16        and by tests which were skipped in r252116 and I now unskipped.
     17
     18        * NetworkProcess/Downloads/cocoa/DownloadCocoa.mm:
     19        (WebKit::Download::resume):
     20        * NetworkProcess/cocoa/NetworkDataTaskCocoa.h:
     21        * NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
     22        (WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
     23        (WebKit::NetworkDataTaskCocoa::~NetworkDataTaskCocoa):
     24        * NetworkProcess/cocoa/NetworkSessionCocoa.h:
     25        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
     26        (-[WKNetworkSessionDelegate initWithSessionWrapper:withCredentials:]):
     27        (-[WKNetworkSessionDelegate sessionInvalidated]):
     28        (-[WKNetworkSessionDelegate existingTask:]):
     29        (-[WKNetworkSessionDelegate sessionCocoa]):
     30        (-[WKNetworkSessionDelegate URLSession:didBecomeInvalidWithError:]):
     31        (-[WKNetworkSessionDelegate URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:]):
     32        (-[WKNetworkSessionDelegate URLSession:task:_schemeUpgraded:completionHandler:]):
     33        (-[WKNetworkSessionDelegate URLSession:dataTask:willCacheResponse:completionHandler:]):
     34        (processServerTrustEvaluation):
     35        (-[WKNetworkSessionDelegate URLSession:task:didReceiveChallenge:completionHandler:]):
     36        (-[WKNetworkSessionDelegate URLSession:task:didCompleteWithError:]):
     37        (-[WKNetworkSessionDelegate URLSession:downloadTask:didFinishDownloadingToURL:]):
     38        (-[WKNetworkSessionDelegate URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:]):
     39        (-[WKNetworkSessionDelegate URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:]):
     40        (-[WKNetworkSessionDelegate URLSession:dataTask:didBecomeDownloadTask:]):
     41        (-[WKNetworkSessionDelegate existingWebSocketTask:]):
     42        (WebKit::SessionWrapper::initialize):
     43        (WebKit::NetworkSessionCocoa::NetworkSessionCocoa):
     44        (WebKit::NetworkSessionCocoa::initializeEphemeralStatelessSession):
     45        (WebKit::NetworkSessionCocoa::sessionWrapperForTask):
     46        (WebKit::NetworkSessionCocoa::isolatedSession):
     47        (WebKit::NetworkSessionCocoa::invalidateAndCancel):
     48        (WebKit::NetworkSessionCocoa::continueDidReceiveChallenge):
     49        (WebKit::NetworkSessionCocoa::createWebSocketTask):
     50        (WebKit::NetworkSessionCocoa::addWebSocketTask):
     51        (WebKit::NetworkSessionCocoa::removeWebSocketTask):
     52        (-[WKNetworkSessionDelegate initWithNetworkSession:withCredentials:]): Deleted.
     53        (WebKit::NetworkSessionCocoa::initializeEphemeralStatelessCookielessSession): Deleted.
     54        (WebKit::NetworkSessionCocoa::session): Deleted.
     55        (WebKit::NetworkSessionCocoa::dataTaskForIdentifier): Deleted.
     56        (WebKit::NetworkSessionCocoa::downloadTaskWithResumeData): Deleted.
     57        (WebKit::NetworkSessionCocoa::addDownloadID): Deleted.
     58        (WebKit::NetworkSessionCocoa::downloadID): Deleted.
     59        (WebKit::NetworkSessionCocoa::takeDownloadID): Deleted.
     60        (WebKit::NetworkSessionCocoa::webSocketDataTaskForIdentifier): Deleted.
     61        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
     62        (-[WKWebsiteDataStore _logUserInteraction:completionHandler:]):
     63        * UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
     64
    1652019-11-07  Peng Liu  <peng.liu6@apple.com>
    266
  • trunk/Source/WebKit/NetworkProcess/AdClickAttributionManager.cpp

    r250053 r252185  
    169169    loadParameters.sourceOrigin = SecurityOrigin::create(conversionReferrerURL);
    170170    loadParameters.parentPID = presentingApplicationPID();
    171     loadParameters.storedCredentialsPolicy = StoredCredentialsPolicy::EphemeralStatelessCookieless;
     171    loadParameters.storedCredentialsPolicy = StoredCredentialsPolicy::EphemeralStateless;
    172172    loadParameters.options = options;
    173173    loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = true;
  • trunk/Source/WebKit/NetworkProcess/Downloads/cocoa/DownloadCocoa.mm

    r250138 r252185  
    7171#endif
    7272
    73     m_downloadTask = cocoaSession.downloadTaskWithResumeData(updatedData);
    74     cocoaSession.addDownloadID(m_downloadTask.get().taskIdentifier, m_downloadID);
     73    m_downloadTask = [cocoaSession.sessionWrapperForDownloads().session downloadTaskWithResumeData:updatedData];
     74    auto taskIdentifier = [m_downloadTask taskIdentifier];
     75    ASSERT(!cocoaSession.sessionWrapperForDownloads().downloadMap.contains(taskIdentifier));
     76    cocoaSession.sessionWrapperForDownloads().downloadMap.add(taskIdentifier, m_downloadID);
    7577    m_downloadTask.get()._pathToDownloadTaskFile = path;
    7678
  • trunk/Source/WebKit/NetworkProcess/NetworkDataTask.cpp

    r249623 r252185  
    159159}
    160160
     161NetworkSession* NetworkDataTask::networkSession()
     162{
     163    return m_session.get();
     164}
     165
    161166} // namespace WebKit
  • trunk/Source/WebKit/NetworkProcess/NetworkDataTask.h

    r249096 r252185  
    134134    PAL::SessionID sessionID() const;
    135135
     136    NetworkSession* networkSession();
     137
    136138protected:
    137139    NetworkDataTask(NetworkSession&, NetworkDataTaskClient&, const WebCore::ResourceRequest&, WebCore::StoredCredentialsPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect, bool dataTaskIsForMainFrameNavigation);
  • trunk/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h

    r252141 r252185  
    3939class Download;
    4040class NetworkSessionCocoa;
     41struct SessionWrapper;
    4142
    4243class NetworkDataTaskCocoa final : public NetworkDataTask {
     
    9091    bool isAlwaysOnLoggingAllowed() const;
    9192
     93    SessionWrapper& m_sessionWrapper;
    9294    RefPtr<SandboxExtension> m_sandboxExtension;
    9395    RetainPtr<NSURLSessionDataTask> m_task;
  • trunk/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm

    r252141 r252185  
    173173NetworkDataTaskCocoa::NetworkDataTaskCocoa(NetworkSession& session, NetworkDataTaskClient& client, const WebCore::ResourceRequest& requestWithCredentials, WebCore::FrameIdentifier frameID, WebCore::PageIdentifier pageID, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ContentSniffingPolicy shouldContentSniff, WebCore::ContentEncodingSniffingPolicy shouldContentEncodingSniff, bool shouldClearReferrerOnHTTPSToHTTPRedirect, PreconnectOnly shouldPreconnectOnly, bool dataTaskIsForMainFrameNavigation, bool dataTaskIsForMainResourceNavigationForAnyFrame, Optional<NetworkActivityTracker> networkActivityTracker)
    174174    : NetworkDataTask(session, client, requestWithCredentials, storedCredentialsPolicy, shouldClearReferrerOnHTTPSToHTTPRedirect, dataTaskIsForMainFrameNavigation)
     175    , m_sessionWrapper(static_cast<NetworkSessionCocoa&>(session).sessionWrapperForTask(requestWithCredentials, storedCredentialsPolicy))
    175176    , m_frameID(frameID)
    176177    , m_pageID(pageID)
     
    207208
    208209    bool shouldBlockCookies = false;
    209     bool needsIsolatedSession = false;
    210     auto firstParty = WebCore::RegistrableDomain(request.firstPartyForCookies());
    211210#if ENABLE(RESOURCE_LOAD_STATISTICS)
    212     shouldBlockCookies = storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless;
     211    shouldBlockCookies = storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::EphemeralStateless;
    213212    if (auto* networkStorageSession = session.networkStorageSession()) {
    214213        if (!shouldBlockCookies)
    215214            shouldBlockCookies = networkStorageSession->shouldBlockCookies(request, frameID, pageID);
    216         // FIXME: <rdar://problem/56921584> needsIsolatedSession should be set here.
    217215    }
    218216#endif
     
    222220    applySniffingPoliciesAndBindRequestToInferfaceIfNeeded(nsRequest, shouldContentSniff == WebCore::ContentSniffingPolicy::SniffContent && !url.isLocalFile(), shouldContentEncodingSniff == WebCore::ContentEncodingSniffingPolicy::Sniff);
    223221
    224     auto& cocoaSession = static_cast<NetworkSessionCocoa&>(*m_session);
    225     if (needsIsolatedSession)
    226         m_task = [cocoaSession.isolatedSession(storedCredentialsPolicy, firstParty) dataTaskWithRequest:nsRequest];
    227     else
    228         m_task = [cocoaSession.session(storedCredentialsPolicy) dataTaskWithRequest:nsRequest];
    229 
    230     LOG(NetworkSession, "%llu Creating NetworkDataTask with storedCredentialsPolicy=%u and URL=%s", [m_task taskIdentifier], storedCredentialsPolicy, nsRequest.URL.absoluteString.UTF8String);
    231     cocoaSession.registerDataTask([m_task taskIdentifier], *this, storedCredentialsPolicy);
     222    m_task = [m_sessionWrapper.session dataTaskWithRequest:nsRequest];
     223
     224    RELEASE_ASSERT(!m_sessionWrapper.dataTaskMap.contains([m_task taskIdentifier]));
     225    m_sessionWrapper.dataTaskMap.add([m_task taskIdentifier], this);
     226    LOG(NetworkSession, "%llu Creating NetworkDataTask with URL %s", [m_task taskIdentifier], nsRequest.URL.absoluteString.UTF8String);
    232227
    233228    if (shouldPreconnectOnly == PreconnectOnly::Yes) {
     
    267262        return;
    268263
    269     auto& cocoaSession = static_cast<NetworkSessionCocoa&>(*m_session);
    270     cocoaSession.unregisterDataTask([m_task taskIdentifier], *this, m_storedCredentialsPolicy);
     264    RELEASE_ASSERT(m_sessionWrapper.dataTaskMap.get([m_task taskIdentifier]) == this);
     265    m_sessionWrapper.dataTaskMap.remove([m_task taskIdentifier]);
    271266}
    272267
     
    358353#if ENABLE(RESOURCE_LOAD_STATISTICS)
    359354    if (!m_hasBeenSetToUseStatelessCookieStorage) {
    360         if (m_storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless
     355        if (m_storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::EphemeralStateless
    361356            || (m_session->networkStorageSession() && m_session->networkStorageSession()->shouldBlockCookies(request, m_frameID, m_pageID)))
    362357            blockCookies();
  • trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h

    r252141 r252185  
    2929OBJC_CLASS NSData;
    3030OBJC_CLASS NSURLSession;
     31OBJC_CLASS NSURLSessionConfiguration;
    3132OBJC_CLASS NSURLSessionDownloadTask;
    3233OBJC_CLASS NSOperationQueue;
     
    4647
    4748class LegacyCustomProtocolManager;
     49class NetworkSessionCocoa;
     50
     51struct SessionWrapper : public CanMakeWeakPtr<SessionWrapper> {
     52    void initialize(NSURLSessionConfiguration *, NetworkSessionCocoa&, WebCore::StoredCredentialsPolicy);
     53
     54    RetainPtr<NSURLSession> session;
     55    RetainPtr<WKNetworkSessionDelegate> delegate;
     56    HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> dataTaskMap;
     57    HashMap<NetworkDataTaskCocoa::TaskIdentifier, DownloadID> downloadMap;
     58#if HAVE(NSURLSESSION_WEBSOCKET)
     59    HashMap<NetworkDataTaskCocoa::TaskIdentifier, WebSocketTask*> webSocketDataTaskMap;
     60#endif
     61};
    4862
    4963class NetworkSessionCocoa final : public NetworkSession {
     
    5569    ~NetworkSessionCocoa();
    5670
    57     void initializeEphemeralStatelessCookielessSession();
     71    void initializeEphemeralStatelessSession();
    5872
    5973    const String& boundInterfaceIdentifier() const;
     
    6478#endif
    6579
    66     NetworkDataTaskCocoa* dataTaskForIdentifier(NetworkDataTaskCocoa::TaskIdentifier, WebCore::StoredCredentialsPolicy);
    67     void registerDataTask(NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa&, WebCore::StoredCredentialsPolicy);
    68     void unregisterDataTask(NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa&, WebCore::StoredCredentialsPolicy);
    69 
    70     NSURLSessionDownloadTask* downloadTaskWithResumeData(NSData*);
    71 
    72     WebSocketTask* webSocketDataTaskForIdentifier(WebSocketTask::TaskIdentifier);
    73 
    74     void addDownloadID(NetworkDataTaskCocoa::TaskIdentifier, DownloadID);
    75     DownloadID downloadID(NetworkDataTaskCocoa::TaskIdentifier);
    76     DownloadID takeDownloadID(NetworkDataTaskCocoa::TaskIdentifier);
    77 
    7880    static bool allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge&);
    7981
    80     void continueDidReceiveChallenge(const WebCore::AuthenticationChallenge&, NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&&);
     82    void continueDidReceiveChallenge(SessionWrapper&, const WebCore::AuthenticationChallenge&, NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&&);
     83
     84    SessionWrapper& sessionWrapperForDownloads() { return m_sessionWithCredentialStorage; }
    8185
    8286    bool fastServerTrustEvaluationEnabled() const { return m_fastServerTrustEvaluationEnabled; }
     
    8791    CFDictionaryRef proxyConfiguration() const { return m_proxyConfiguration.get(); }
    8892
    89     NSURLSession* session(WebCore::StoredCredentialsPolicy);
    90     NSURLSession* isolatedSession(WebCore::StoredCredentialsPolicy, const WebCore::RegistrableDomain);
    9193    bool hasIsolatedSession(const WebCore::RegistrableDomain) const override;
    9294    void clearIsolatedSessions() override;
     
    9799    bool shouldLogCookieInformation() const override { return m_shouldLogCookieInformation; }
    98100    Seconds loadThrottleLatency() const override { return m_loadThrottleLatency; }
     101    SessionWrapper& sessionWrapperForTask(const WebCore::ResourceRequest&, WebCore::StoredCredentialsPolicy);
     102    SessionWrapper& isolatedSession(WebCore::StoredCredentialsPolicy, const WebCore::RegistrableDomain);
    99103
    100104#if HAVE(NSURLSESSION_WEBSOCKET)
     
    104108#endif
    105109
    106     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*>& dataTaskMap(WebCore::StoredCredentialsPolicy);
    107 
    108     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> m_dataTaskMapWithCredentials;
    109     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> m_dataTaskMapWithoutState;
    110     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> m_dataTaskMapEphemeralStatelessCookieless;
    111     HashMap<NetworkDataTaskCocoa::TaskIdentifier, DownloadID> m_downloadMap;
    112 #if HAVE(NSURLSESSION_WEBSOCKET)
    113     HashMap<NetworkDataTaskCocoa::TaskIdentifier, WebSocketTask*> m_webSocketDataTaskMap;
    114 #endif
    115 
    116110    struct IsolatedSession {
    117         RetainPtr<NSURLSession> sessionWithCredentialStorage;
    118         RetainPtr<WKNetworkSessionDelegate> sessionWithCredentialStorageDelegate;
    119         RetainPtr<NSURLSession> statelessSession;
    120         RetainPtr<WKNetworkSessionDelegate> statelessSessionDelegate;
     111        WTF_MAKE_FAST_ALLOCATED;
     112    public:
     113        SessionWrapper sessionWithCredentialStorage;
     114        SessionWrapper sessionWithoutCredentialStorage;
    121115        WallTime lastUsed;
    122116    };
    123117
    124     HashMap<WebCore::RegistrableDomain, IsolatedSession> m_isolatedSessions;
     118    HashMap<WebCore::RegistrableDomain, std::unique_ptr<IsolatedSession>> m_isolatedSessions;
    125119
    126     RetainPtr<NSURLSession> m_sessionWithCredentialStorage;
    127     RetainPtr<WKNetworkSessionDelegate> m_sessionWithCredentialStorageDelegate;
    128     RetainPtr<NSURLSession> m_statelessSession;
    129     RetainPtr<WKNetworkSessionDelegate> m_statelessSessionDelegate;
    130     RetainPtr<NSURLSession> m_ephemeralStatelessCookielessSession;
    131     RetainPtr<WKNetworkSessionDelegate> m_ephemeralStatelessCookielessSessionDelegate;
     120    SessionWrapper m_sessionWithCredentialStorage;
     121    SessionWrapper m_sessionWithoutCredentialStorage;
     122    SessionWrapper m_ephemeralStatelessSession;
    132123
    133124    String m_boundInterfaceIdentifier;
  • trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm

    r252141 r252185  
    4949#import <WebCore/WebCoreURLResponse.h>
    5050#import <pal/spi/cf/CFNetworkSPI.h>
     51#import <wtf/BlockPtr.h>
    5152#import <wtf/MainThread.h>
    5253#import <wtf/NeverDestroyed.h>
     
    5556#import <wtf/SoftLinking.h>
    5657#import <wtf/URL.h>
     58#import <wtf/WeakObjCPtr.h>
    5759#import <wtf/text/WTFString.h>
    58 #import <wtf/BlockPtr.h>
    5960
    6061#if USE(APPLE_INTERNAL_SDK)
     
    397398> {
    398399    WeakPtr<WebKit::NetworkSessionCocoa> _session;
     400    WeakPtr<WebKit::SessionWrapper> _sessionWrapper;
    399401    bool _withCredentials;
    400402}
    401403
    402 - (id)initWithNetworkSession:(WebKit::NetworkSessionCocoa&)session withCredentials:(bool)withCredentials;
     404- (id)initWithNetworkSession:(WebKit::NetworkSessionCocoa&)session wrapper:(WebKit::SessionWrapper&)sessionWrapper withCredentials:(bool)withCredentials;
    403405- (void)sessionInvalidated;
    404406
     
    407409@implementation WKNetworkSessionDelegate
    408410
    409 - (id)initWithNetworkSession:(WebKit::NetworkSessionCocoa&)session withCredentials:(bool)withCredentials
     411- (id)initWithNetworkSession:(WebKit::NetworkSessionCocoa&)session wrapper:(WebKit::SessionWrapper&)sessionWrapper withCredentials:(bool)withCredentials
    410412{
    411413    self = [super init];
     
    414416
    415417    _session = makeWeakPtr(session);
     418    _sessionWrapper = makeWeakPtr(sessionWrapper);
    416419    _withCredentials = withCredentials;
    417420
     
    421424- (void)sessionInvalidated
    422425{
    423     _session = nullptr;
     426    _sessionWrapper = nullptr;
    424427}
    425428
    426429- (NetworkDataTaskCocoa*)existingTask:(NSURLSessionTask *)task
    427430{
    428     if (!_session)
     431    if (!_sessionWrapper)
    429432        return nullptr;
    430433
     
    432435        return nullptr;
    433436
    434     auto storedCredentialsPolicy = _withCredentials ? WebCore::StoredCredentialsPolicy::Use : WebCore::StoredCredentialsPolicy::DoNotUse;
    435     return _session->dataTaskForIdentifier(task.taskIdentifier, storedCredentialsPolicy);
     437    return _sessionWrapper->dataTaskMap.get(task.taskIdentifier);
    436438}
    437439
    438440- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
    439441{
    440     ASSERT(!_session);
     442    ASSERT(!_sessionWrapper);
    441443}
    442444
     
    528530        bool shouldIgnoreHSTS = false;
    529531#if ENABLE(RESOURCE_LOAD_STATISTICS)
    530         shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && _session->networkProcess().storageSession(_session->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID());
    531         if (shouldIgnoreHSTS) {
    532             request = downgradeRequest(request);
    533             ASSERT([request.URL.scheme isEqualToString:@"http"]);
    534             LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
    535         }
     532        if (auto* sessionCocoa = networkDataTask->networkSession()) {
     533            shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && sessionCocoa->networkProcess().storageSession(sessionCocoa->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID());
     534            if (shouldIgnoreHSTS) {
     535                request = downgradeRequest(request);
     536                ASSERT([request.URL.scheme isEqualToString:@"http"]);
     537                LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
     538            }
     539        } else
     540            ASSERT_NOT_REACHED();
    536541#endif
    537542
     
    561566        bool shouldIgnoreHSTS = false;
    562567#if ENABLE(RESOURCE_LOAD_STATISTICS)
    563         shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && _session->networkProcess().storageSession(_session->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID());
    564         if (shouldIgnoreHSTS) {
    565             request = downgradeRequest(request);
    566             ASSERT([request.URL.scheme isEqualToString:@"http"]);
    567             LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
    568         }
     568        if (auto* sessionCocoa = networkDataTask->networkSession()) {
     569            shouldIgnoreHSTS = schemeWasUpgradedDueToDynamicHSTS(request) && sessionCocoa->networkProcess().storageSession(sessionCocoa->sessionID())->shouldBlockCookies(request, networkDataTask->frameID(), networkDataTask->pageID());
     570            if (shouldIgnoreHSTS) {
     571                request = downgradeRequest(request);
     572                ASSERT([request.URL.scheme isEqualToString:@"http"]);
     573                LOG(NetworkSession, "%llu Downgraded %s from https to http", taskIdentifier, request.URL.absoluteString.UTF8String);
     574            }
     575        } else
     576            ASSERT_NOT_REACHED();
    569577#endif
    570578
     
    589597- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
    590598{
    591     if (!_session) {
    592         completionHandler(nil);
    593         return;
    594     }
    595 
    596599    // FIXME: remove if <rdar://problem/20001985> is ever resolved.
    597600    if ([proposedResponse.response respondsToSelector:@selector(allHeaderFields)]
     
    603606
    604607#if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
    605 static inline void processServerTrustEvaluation(NetworkSessionCocoa *session, NSURLAuthenticationChallenge *challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential)>&& completionHandler)
    606 {
    607     session->continueDidReceiveChallenge(challenge, taskIdentifier, networkDataTask, [completionHandler = WTFMove(completionHandler), secTrust = retainPtr(challenge.protectionSpace.serverTrust)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
     608static inline void processServerTrustEvaluation(NetworkSessionCocoa *session, SessionWrapper& sessionWrapper, NSURLAuthenticationChallenge *challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential)>&& completionHandler)
     609{
     610    session->continueDidReceiveChallenge(sessionWrapper, challenge, taskIdentifier, networkDataTask, [completionHandler = WTFMove(completionHandler), secTrust = retainPtr(challenge.protectionSpace.serverTrust)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
    608611        // FIXME: UIProcess should send us back non nil credentials but the credential IPC encoder currently only serializes ns credentials for username/password.
    609612        if (disposition == WebKit::AuthenticationChallengeDisposition::UseCredential && !credential.nsCredential()) {
     
    618621- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
    619622{
    620     if (!_session || [task state] == NSURLSessionTaskStateCanceling) {
     623    auto* networkDataTask = [self existingTask:task];
     624    auto* sessionCocoa = networkDataTask ? static_cast<NetworkSessionCocoa*>(networkDataTask->networkSession()) : nullptr;
     625    if (!sessionCocoa || [task state] == NSURLSessionTaskStateCanceling) {
    621626        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
    622627        return;
     
    638643
    639644        // Handle server trust evaluation at platform-level if requested, for performance reasons and to use ATS defaults.
    640         if (_session->fastServerTrustEvaluationEnabled()) {
     645        if (sessionCocoa->fastServerTrustEvaluationEnabled()) {
    641646#if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
    642647            auto* networkDataTask = [self existingTask:task];
    643648            ASSERT(networkDataTask);
    644             auto decisionHandler = makeBlockPtr([_session = makeWeakPtr(_session.get()), completionHandler = makeBlockPtr(completionHandler), taskIdentifier, networkDataTask = RefPtr<NetworkDataTaskCocoa>(networkDataTask)](NSURLAuthenticationChallenge *challenge, OSStatus trustResult) mutable {
     649            auto decisionHandler = makeBlockPtr([weakSelf = WeakObjCPtr<WKNetworkSessionDelegate>(self), sessionCocoa = makeWeakPtr(sessionCocoa), completionHandler = makeBlockPtr(completionHandler), taskIdentifier, networkDataTask = RefPtr<NetworkDataTaskCocoa>(networkDataTask)](NSURLAuthenticationChallenge *challenge, OSStatus trustResult) mutable {
     650                auto strongSelf = weakSelf.get();
     651                if (!strongSelf)
     652                    return completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
    645653                auto task = WTFMove(networkDataTask);
    646                 auto* session = _session.get();
     654                auto* session = sessionCocoa.get();
    647655                if (trustResult == noErr || !session) {
    648656                    completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
    649657                    return;
    650658                }
    651                 processServerTrustEvaluation(session, challenge, taskIdentifier, task.get(), WTFMove(completionHandler));
     659                processServerTrustEvaluation(session, *strongSelf->_sessionWrapper, challenge, taskIdentifier, task.get(), WTFMove(completionHandler));
    652660            });
    653661            [NSURLSession _strictTrustEvaluate:challenge queue:[NSOperationQueue mainQueue].underlyingQueue completionHandler:decisionHandler.get()];
     
    658666        }
    659667    }
    660     _session->continueDidReceiveChallenge(challenge, taskIdentifier, [self existingTask:task], [completionHandler = makeBlockPtr(completionHandler)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
     668    sessionCocoa->continueDidReceiveChallenge(*_sessionWrapper, challenge, taskIdentifier, [self existingTask:task], [completionHandler = makeBlockPtr(completionHandler)] (WebKit::AuthenticationChallengeDisposition disposition, const WebCore::Credential& credential) mutable {
    661669        completionHandler(toNSURLSessionAuthChallengeDisposition(disposition), credential.nsCredential());
    662670    });
     
    665673- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
    666674{
    667     if (!_session)
    668         return;
    669 
    670675    LOG(NetworkSession, "%llu didCompleteWithError %@", task.taskIdentifier, error);
    671676
     
    680685        networkDataTask->didCompleteWithError(error, networkDataTask->networkLoadMetrics());
    681686    else if (error) {
    682         auto downloadID = _session->takeDownloadID(task.taskIdentifier);
    683         if (downloadID.downloadID()) {
    684             if (auto* download = _session->networkProcess().downloadManager().download(downloadID)) {
    685                 NSData *resumeData = nil;
    686                 if (id userInfo = error.userInfo) {
    687                     if ([userInfo isKindOfClass:[NSDictionary class]]) {
    688                         resumeData = userInfo[@"NSURLSessionDownloadTaskResumeData"];
    689                         if (resumeData && ![resumeData isKindOfClass:[NSData class]]) {
    690                             RELEASE_LOG(NetworkSession, "Download task %llu finished with resume data of wrong class: %s", (unsigned long long)task.taskIdentifier, NSStringFromClass([resumeData class]).UTF8String);
    691                             ASSERT_NOT_REACHED();
    692                             resumeData = nil;
    693                         }
    694                     }
     687        if (!_sessionWrapper)
     688            return;
     689        auto downloadID = _sessionWrapper->downloadMap.take(task.taskIdentifier);
     690        if (!downloadID.downloadID())
     691            return;
     692        if (!_session)
     693            return;
     694        auto* download = _session->networkProcess().downloadManager().download(downloadID);
     695        if (!download)
     696            return;
     697
     698        NSData *resumeData = nil;
     699        if (id userInfo = error.userInfo) {
     700            if ([userInfo isKindOfClass:[NSDictionary class]]) {
     701                resumeData = userInfo[@"NSURLSessionDownloadTaskResumeData"];
     702                if (resumeData && ![resumeData isKindOfClass:[NSData class]]) {
     703                    RELEASE_LOG(NetworkSession, "Download task %llu finished with resume data of wrong class: %s", (unsigned long long)task.taskIdentifier, NSStringFromClass([resumeData class]).UTF8String);
     704                    ASSERT_NOT_REACHED();
     705                    resumeData = nil;
    695706                }
    696 
    697                 auto resumeDataReference = resumeData ? IPC::DataReference { static_cast<const uint8_t*>(resumeData.bytes), resumeData.length } : IPC::DataReference { };
    698 
    699                 if (download->wasCanceled())
    700                     download->didCancel(resumeDataReference);
    701                 else
    702                     download->didFail(error, resumeDataReference);
    703707            }
    704708        }
     709
     710        auto resumeDataReference = resumeData ? IPC::DataReference { static_cast<const uint8_t*>(resumeData.bytes), resumeData.length } : IPC::DataReference { };
     711
     712        if (download->wasCanceled())
     713            download->didCancel(resumeDataReference);
     714        else
     715            download->didFail(error, resumeDataReference);
    705716    }
    706717}
     
    837848- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
    838849{
     850    if (!_sessionWrapper)
     851        return;
     852    auto downloadID = _sessionWrapper->downloadMap.take([downloadTask taskIdentifier]);
     853    if (!downloadID.downloadID())
     854        return;
    839855    if (!_session)
    840856        return;
    841 
    842     auto downloadID = _session->takeDownloadID([downloadTask taskIdentifier]);
    843     if (auto* download = _session->networkProcess().downloadManager().download(downloadID))
    844         download->didFinish();
     857    auto* download = _session->networkProcess().downloadManager().download(downloadID);
     858    if (!download)
     859        return;
     860    download->didFinish();
    845861}
    846862
    847863- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
    848864{
     865    ASSERT_WITH_MESSAGE(![self existingTask:downloadTask], "The NetworkDataTask should be destroyed immediately after didBecomeDownloadTask returns");
     866
     867    if (!_sessionWrapper)
     868        return;
     869    auto downloadID = _sessionWrapper->downloadMap.get([downloadTask taskIdentifier]);
     870    if (!downloadID.downloadID())
     871        return;
    849872    if (!_session)
    850873        return;
    851 
    852     ASSERT_WITH_MESSAGE(![self existingTask:downloadTask], "The NetworkDataTask should be destroyed immediately after didBecomeDownloadTask returns");
    853 
    854     auto downloadID = _session->downloadID([downloadTask taskIdentifier]);
    855     if (auto* download = _session->networkProcess().downloadManager().download(downloadID))
    856         download->didReceiveData(bytesWritten);
     874    auto* download = _session->networkProcess().downloadManager().download(downloadID);
     875    if (!download)
     876        return;
     877    download->didReceiveData(bytesWritten);
    857878}
    858879
    859880- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
    860881{
    861     if (!_session)
    862         return;
    863 
    864882    notImplemented();
    865883}
     
    867885- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
    868886{
    869     if (auto* networkDataTask = [self existingTask:dataTask]) {
    870         Ref<NetworkDataTaskCocoa> protectedNetworkDataTask(*networkDataTask);
    871         auto downloadID = networkDataTask->pendingDownloadID();
    872         auto& downloadManager = _session->networkProcess().downloadManager();
    873         auto download = makeUnique<WebKit::Download>(downloadManager, downloadID, downloadTask, *_session, networkDataTask->suggestedFilename());
    874         networkDataTask->transferSandboxExtensionToDownload(*download);
    875         ASSERT(FileSystem::fileExists(networkDataTask->pendingDownloadLocation()));
    876         download->didCreateDestination(networkDataTask->pendingDownloadLocation());
    877         downloadManager.dataTaskBecameDownloadTask(downloadID, WTFMove(download));
    878 
    879         _session->addDownloadID([downloadTask taskIdentifier], downloadID);
    880     }
     887    auto* networkDataTask = [self existingTask:dataTask];
     888    if (!networkDataTask)
     889        return;
     890    auto* sessionCocoa = networkDataTask->networkSession();
     891    if (!sessionCocoa)
     892        return;
     893
     894    Ref<NetworkDataTaskCocoa> protectedNetworkDataTask(*networkDataTask);
     895    auto downloadID = networkDataTask->pendingDownloadID();
     896    auto& downloadManager = sessionCocoa->networkProcess().downloadManager();
     897    auto download = makeUnique<WebKit::Download>(downloadManager, downloadID, downloadTask, *sessionCocoa, networkDataTask->suggestedFilename());
     898    networkDataTask->transferSandboxExtensionToDownload(*download);
     899    ASSERT(FileSystem::fileExists(networkDataTask->pendingDownloadLocation()));
     900    download->didCreateDestination(networkDataTask->pendingDownloadLocation());
     901    downloadManager.dataTaskBecameDownloadTask(downloadID, WTFMove(download));
     902
     903    RELEASE_ASSERT(!_sessionWrapper->downloadMap.contains(downloadTask.taskIdentifier));
     904    _sessionWrapper->downloadMap.add(downloadTask.taskIdentifier, downloadID);
    881905}
    882906
     
    884908- (WebSocketTask*)existingWebSocketTask:(NSURLSessionWebSocketTask *)task
    885909{
    886     if (!_session)
     910    if (!_sessionWrapper)
    887911        return nullptr;
    888912
     
    890914        return nullptr;
    891915
    892     return _session->webSocketDataTaskForIdentifier(task.taskIdentifier);
     916    return _sessionWrapper->webSocketDataTaskMap.get(task.taskIdentifier);
    893917}
    894918
     
    971995
    972996    ALLOW_DEPRECATED_DECLARATIONS_END
     997}
     998
     999void SessionWrapper::initialize(NSURLSessionConfiguration *configuration, NetworkSessionCocoa& networkSession, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
     1000{
     1001    delegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:networkSession wrapper:*this withCredentials:storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use]);
     1002    session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate.get() delegateQueue:[NSOperationQueue mainQueue]];
    9731003}
    9741004
     
    10641094#endif
    10651095
    1066     m_sessionWithCredentialStorageDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:true]);
    1067     m_sessionWithCredentialStorage = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_sessionWithCredentialStorageDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
     1096    m_sessionWithCredentialStorage.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::Use);
    10681097    LOG(NetworkSession, "Created NetworkSession with cookieAcceptPolicy %lu", configuration.HTTPCookieStorage.cookieAcceptPolicy);
    10691098
     
    10741103    // configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
    10751104
    1076     m_statelessSessionDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:false]);
    1077     m_statelessSession = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_statelessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
     1105    m_sessionWithoutCredentialStorage.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::DoNotUse);
    10781106
    10791107    m_deviceManagementRestrictionsEnabled = parameters.deviceManagementRestrictionsEnabled;
     
    10981126}
    10991127
    1100 void NetworkSessionCocoa::initializeEphemeralStatelessCookielessSession()
     1128void NetworkSessionCocoa::initializeEphemeralStatelessSession()
    11011129{
    11021130    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    1103     NSURLSessionConfiguration *existingConfiguration = m_statelessSession.get().configuration;
     1131    NSURLSessionConfiguration *existingConfiguration = m_sessionWithoutCredentialStorage.session.get().configuration;
    11041132
    11051133    configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
     
    11161144#endif
    11171145
    1118     m_ephemeralStatelessCookielessSessionDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:false]);
    1119     m_ephemeralStatelessCookielessSession = [NSURLSession sessionWithConfiguration:configuration delegate:static_cast<id>(m_ephemeralStatelessCookielessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
    1120 }
    1121 
    1122 NSURLSession* NetworkSessionCocoa::session(WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
    1123 {
     1146    m_ephemeralStatelessSession.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::EphemeralStateless);
     1147}
     1148
     1149SessionWrapper& NetworkSessionCocoa::sessionWrapperForTask(const WebCore::ResourceRequest& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
     1150{
     1151#if ENABLE(RESOURCE_LOAD_STATISTICS)
     1152    if (auto* storageSession = networkStorageSession()) {
     1153        auto firstParty = WebCore::RegistrableDomain(request.firstPartyForCookies());
     1154        if (storageSession->shouldBlockThirdPartyCookiesButKeepFirstPartyCookiesFor(firstParty))
     1155            return isolatedSession(storedCredentialsPolicy, firstParty);
     1156    } else
     1157        ASSERT_NOT_REACHED();
     1158#endif
     1159
    11241160    switch (storedCredentialsPolicy) {
    11251161    case WebCore::StoredCredentialsPolicy::Use:
    1126         return m_sessionWithCredentialStorage.get();
     1162        return m_sessionWithCredentialStorage;
    11271163    case WebCore::StoredCredentialsPolicy::DoNotUse:
    1128         return m_statelessSession.get();
    1129     case WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless:
    1130         if (!m_ephemeralStatelessCookielessSession)
    1131             initializeEphemeralStatelessCookielessSession();
    1132         return m_ephemeralStatelessCookielessSession.get();
    1133     }
    1134 }
    1135 
    1136 NSURLSession* NetworkSessionCocoa::isolatedSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy, const WebCore::RegistrableDomain firstPartyDomain)
    1137 {
    1138     auto entry = m_isolatedSessions.ensure(firstPartyDomain, [this] {
    1139         IsolatedSession newEntry { };
    1140         newEntry.sessionWithCredentialStorageDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:true]);
    1141         newEntry.sessionWithCredentialStorage = [NSURLSession sessionWithConfiguration:m_sessionWithCredentialStorage.get().configuration delegate:static_cast<id>(newEntry.sessionWithCredentialStorageDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
    1142 
    1143         newEntry.statelessSessionDelegate = adoptNS([[WKNetworkSessionDelegate alloc] initWithNetworkSession:*this withCredentials:false]);
    1144         newEntry.statelessSession = [NSURLSession sessionWithConfiguration:m_statelessSession.get().configuration delegate:static_cast<id>(newEntry.statelessSessionDelegate.get()) delegateQueue:[NSOperationQueue mainQueue]];
    1145 
     1164        return m_sessionWithoutCredentialStorage;
     1165    case WebCore::StoredCredentialsPolicy::EphemeralStateless:
     1166        if (!m_ephemeralStatelessSession.session)
     1167            initializeEphemeralStatelessSession();
     1168        return m_ephemeralStatelessSession;
     1169    }
     1170}
     1171
     1172SessionWrapper& NetworkSessionCocoa::isolatedSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy, const WebCore::RegistrableDomain firstPartyDomain)
     1173{
     1174    auto& entry = m_isolatedSessions.ensure(firstPartyDomain, [this] {
     1175        auto newEntry = makeUnique<IsolatedSession>();
     1176        newEntry->sessionWithCredentialStorage.initialize(m_sessionWithCredentialStorage.session.get().configuration, *this, WebCore::StoredCredentialsPolicy::Use);
     1177        newEntry->sessionWithoutCredentialStorage.initialize(m_sessionWithoutCredentialStorage.session.get().configuration, *this, WebCore::StoredCredentialsPolicy::DoNotUse);
    11461178        return newEntry;
    11471179    }).iterator->value;
    11481180
    1149     entry.lastUsed = WallTime::now();
     1181    entry->lastUsed = WallTime::now();
    11501182
    11511183    if (m_isolatedSessions.size() > maxNumberOfIsolatedSessions) {
     
    11531185        auto oldestTimestamp = WallTime::now();
    11541186        for (auto& key : m_isolatedSessions.keys()) {
    1155             auto timestamp = m_isolatedSessions.get(key).lastUsed;
     1187            auto timestamp = m_isolatedSessions.get(key)->lastUsed;
    11561188            if (timestamp < oldestTimestamp) {
    11571189                oldestTimestamp = timestamp;
     
    11681200    case WebCore::StoredCredentialsPolicy::Use:
    11691201        LOG(NetworkSession, "Using isolated NSURLSession with credential storage.");
    1170         return entry.sessionWithCredentialStorage.get();
     1202        return entry->sessionWithCredentialStorage;
    11711203    case WebCore::StoredCredentialsPolicy::DoNotUse:
    11721204        LOG(NetworkSession, "Using isolated NSURLSession without credential storage.");
    1173         return entry.statelessSession.get();
    1174     case WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless:
    1175         if (!m_ephemeralStatelessCookielessSession)
    1176             initializeEphemeralStatelessCookielessSession();
    1177         return m_ephemeralStatelessCookielessSession.get();
     1205        return entry->sessionWithoutCredentialStorage;
     1206    case WebCore::StoredCredentialsPolicy::EphemeralStateless:
     1207        if (!m_ephemeralStatelessSession.session)
     1208            initializeEphemeralStatelessSession();
     1209        return m_ephemeralStatelessSession;
    11781210    }
    11791211}
     
    11931225    NetworkSession::invalidateAndCancel();
    11941226
    1195     [m_sessionWithCredentialStorage invalidateAndCancel];
    1196     [m_statelessSession invalidateAndCancel];
    1197     [m_ephemeralStatelessCookielessSession invalidateAndCancel];
    1198     [m_sessionWithCredentialStorageDelegate sessionInvalidated];
    1199     [m_statelessSessionDelegate sessionInvalidated];
    1200     [m_ephemeralStatelessCookielessSessionDelegate sessionInvalidated];
     1227    [m_sessionWithCredentialStorage.session invalidateAndCancel];
     1228    [m_sessionWithoutCredentialStorage.session invalidateAndCancel];
     1229    [m_ephemeralStatelessSession.session invalidateAndCancel];
     1230    [m_sessionWithCredentialStorage.delegate sessionInvalidated];
     1231    [m_sessionWithoutCredentialStorage.delegate sessionInvalidated];
     1232    [m_ephemeralStatelessSession.delegate sessionInvalidated];
    12011233
    12021234    for (auto& session : m_isolatedSessions.values()) {
    1203         [session.sessionWithCredentialStorage invalidateAndCancel];
    1204         [session.sessionWithCredentialStorageDelegate sessionInvalidated];
     1235        [session->sessionWithCredentialStorage.session invalidateAndCancel];
     1236        [session->sessionWithCredentialStorage.delegate sessionInvalidated];
     1237        [session->sessionWithoutCredentialStorage.session invalidateAndCancel];
     1238        [session->sessionWithoutCredentialStorage.delegate sessionInvalidated];
    12051239    }
    12061240    m_isolatedSessions.clear();
     
    12211255}
    12221256
    1223 HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*>& NetworkSessionCocoa::dataTaskMap(WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
    1224 {
    1225     ASSERT(RunLoop::isMain());
    1226     switch (storedCredentialsPolicy) {
    1227     case WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless:
    1228         return m_dataTaskMapEphemeralStatelessCookieless;
    1229     case WebCore::StoredCredentialsPolicy::DoNotUse:
    1230         return m_dataTaskMapWithoutState;
    1231     case WebCore::StoredCredentialsPolicy::Use:
    1232         return m_dataTaskMapWithCredentials;
    1233     }
    1234     ASSERT_NOT_REACHED();
    1235     return m_dataTaskMapWithCredentials;
    1236 }
    1237 
    1238 NetworkDataTaskCocoa* NetworkSessionCocoa::dataTaskForIdentifier(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
    1239 {
    1240     ASSERT(RunLoop::isMain());
    1241     return dataTaskMap(storedCredentialsPolicy).get(taskIdentifier);
    1242 }
    1243 
    1244 void NetworkSessionCocoa::registerDataTask(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa& dataTask, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
    1245 {
    1246     auto& map = dataTaskMap(storedCredentialsPolicy);
    1247     RELEASE_ASSERT(!map.contains(taskIdentifier));
    1248     map.add(taskIdentifier, &dataTask);
    1249 }
    1250 
    1251 void NetworkSessionCocoa::unregisterDataTask(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa& dataTask, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
    1252 {
    1253     auto& map = dataTaskMap(storedCredentialsPolicy);
    1254     RELEASE_ASSERT(map.get(taskIdentifier) == &dataTask);
    1255     map.remove(taskIdentifier);
    1256 }
    1257 
    1258 NSURLSessionDownloadTask* NetworkSessionCocoa::downloadTaskWithResumeData(NSData* resumeData)
    1259 {
    1260     return [m_sessionWithCredentialStorage downloadTaskWithResumeData:resumeData];
    1261 }
    1262 
    1263 void NetworkSessionCocoa::addDownloadID(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, DownloadID downloadID)
    1264 {
    1265 #ifndef NDEBUG
    1266     ASSERT(!m_downloadMap.contains(taskIdentifier));
    1267     for (auto idInMap : m_downloadMap.values())
    1268         ASSERT(idInMap != downloadID);
    1269 #endif
    1270     m_downloadMap.add(taskIdentifier, downloadID);
    1271 }
    1272 
    1273 DownloadID NetworkSessionCocoa::downloadID(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier)
    1274 {
    1275     ASSERT(m_downloadMap.get(taskIdentifier).downloadID());
    1276     return m_downloadMap.get(taskIdentifier);
    1277 }
    1278 
    1279 DownloadID NetworkSessionCocoa::takeDownloadID(NetworkDataTaskCocoa::TaskIdentifier taskIdentifier)
    1280 {
    1281     auto downloadID = m_downloadMap.take(taskIdentifier);
    1282     return downloadID;
    1283 }
    1284 
    12851257static bool certificatesMatch(SecTrustRef trust1, SecTrustRef trust2)
    12861258{
     
    13231295}
    13241296
    1325 void NetworkSessionCocoa::continueDidReceiveChallenge(const WebCore::AuthenticationChallenge& challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&& completionHandler)
     1297void NetworkSessionCocoa::continueDidReceiveChallenge(SessionWrapper& sessionWrapper, const WebCore::AuthenticationChallenge& challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&& completionHandler)
    13261298{
    13271299    if (!networkDataTask) {
    13281300#if HAVE(NSURLSESSION_WEBSOCKET)
    1329         if (auto* webSocketTask = webSocketDataTaskForIdentifier(taskIdentifier)) {
     1301        if (auto* webSocketTask = sessionWrapper.webSocketDataTaskMap.get(taskIdentifier)) {
    13301302            // FIXME: Handle challenges for web socket.
    13311303            completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, { });
     
    13331305        }
    13341306#endif
    1335 
    1336         auto downloadID = this->downloadID(taskIdentifier);
     1307        auto downloadID = sessionWrapper.downloadMap.get(taskIdentifier);
    13371308        if (downloadID.downloadID()) {
    13381309            if (auto* download = networkProcess().downloadManager().download(downloadID)) {
     
    13961367{
    13971368    // FIXME: Use protocol.
    1398     RetainPtr<NSURLSessionWebSocketTask> task = [m_sessionWithCredentialStorage.get() webSocketTaskWithRequest: request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)];
     1369    RetainPtr<NSURLSessionWebSocketTask> task = [m_sessionWithCredentialStorage.session webSocketTaskWithRequest:request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)];
    13991370    return makeUnique<WebSocketTask>(channel, WTFMove(task));
    14001371}
     
    14021373void NetworkSessionCocoa::addWebSocketTask(WebSocketTask& task)
    14031374{
    1404     ASSERT(!m_webSocketDataTaskMap.contains(task.identifier()));
    1405     m_webSocketDataTaskMap.add(task.identifier(), &task);
     1375    RELEASE_ASSERT(!m_sessionWithCredentialStorage.webSocketDataTaskMap.contains(task.identifier()));
     1376    m_sessionWithCredentialStorage.webSocketDataTaskMap.add(task.identifier(), &task);
    14061377}
    14071378
    14081379void NetworkSessionCocoa::removeWebSocketTask(WebSocketTask& task)
    14091380{
    1410     ASSERT(m_webSocketDataTaskMap.contains(task.identifier()));
    1411     m_webSocketDataTaskMap.remove(task.identifier());
    1412 }
    1413 
    1414 WebSocketTask* NetworkSessionCocoa::webSocketDataTaskForIdentifier(WebSocketTask::TaskIdentifier identifier)
    1415 {
    1416     return m_webSocketDataTaskMap.get(identifier);
    1417 }
    1418 
    1419 #endif
    1420 }
     1381    RELEASE_ASSERT(m_sessionWithCredentialStorage.webSocketDataTaskMap.contains(task.identifier()));
     1382    m_sessionWithCredentialStorage.webSocketDataTaskMap.remove(task.identifier());
     1383}
     1384
     1385#endif // HAVE(NSURLSESSION_WEBSOCKET)
     1386
     1387}
  • trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h

    r251361 r252185  
    880880        WebCore::StoredCredentialsPolicy::DoNotUse,
    881881        WebCore::StoredCredentialsPolicy::Use,
    882         WebCore::StoredCredentialsPolicy::EphemeralStatelessCookieless
     882        WebCore::StoredCredentialsPolicy::EphemeralStateless
    883883    >;
    884884};
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm

    r252014 r252185  
    464464}
    465465
     466- (void)_logUserInteraction:(NSURL *)domain completionHandler:(void (^)(void))completionHandler
     467{
     468#if ENABLE(RESOURCE_LOAD_STATISTICS)
     469    _websiteDataStore->logUserInteraction(domain, [completionHandler = makeBlockPtr(completionHandler)] {
     470        completionHandler();
     471    });
     472#else
     473    completionHandler();
     474#endif
     475}
     476
    466477- (void)_setPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(void))completionHandler
    467478{
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h

    r252174 r252185  
    6969
    7070- (void)_scheduleCookieBlockingUpdate:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(10.15), ios(13.0));
     71- (void)_logUserInteraction:(NSURL *)domain completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    7172- (void)_setPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(10.15), ios(13.0));
    7273- (void)_getIsPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(BOOL))completionHandler WK_API_AVAILABLE(macos(10.15), ios(13.0));
  • trunk/Tools/ChangeLog

    r252184 r252185  
     12019-11-07  Alex Christensen  <achristensen@webkit.org>
     2
     3        Re-enable NSURLSession isolation after r252116
     4        https://bugs.webkit.org/show_bug.cgi?id=203934
     5        <rdar://problem/56921584>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * TestWebKitAPI/Tests/WebKitCocoa/ResourceLoadStatistics.mm:
     10        (-[DataTaskIdentifierCollisionDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
     11        (-[DataTaskIdentifierCollisionDelegate waitForMessages:]):
     12        (-[DataTaskIdentifierCollisionDelegate webView:didReceiveAuthenticationChallenge:completionHandler:]):
     13        (TEST):
     14
    1152019-11-07  Paulo Matos  <pmatos@igalia.com>
    216
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ResourceLoadStatistics.mm

    r252014 r252185  
    2727
    2828#import "PlatformUtilities.h"
     29#import "TCPServer.h"
    2930#import "TestNavigationDelegate.h"
    3031#import "TestWKWebView.h"
     
    475476}
    476477
     478@interface DataTaskIdentifierCollisionDelegate : NSObject <WKNavigationDelegate, WKUIDelegate>
     479- (NSArray<NSString *> *)waitForMessages:(size_t)count;
     480@end
     481
     482@implementation DataTaskIdentifierCollisionDelegate {
     483    RetainPtr<NSMutableArray<NSString *>> _messages;
     484}
     485
     486- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
     487{
     488    [_messages addObject:message];
     489    completionHandler();
     490}
     491
     492- (NSArray<NSString *> *)waitForMessages:(size_t)messageCount
     493{
     494    _messages = adoptNS([NSMutableArray arrayWithCapacity:messageCount]);
     495    while ([_messages count] < messageCount)
     496        TestWebKitAPI::Util::spinRunLoop();
     497    return _messages.autorelease();
     498}
     499
     500- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * credential))completionHandler
     501{
     502    completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
     503}
     504
     505@end
     506
     507TEST(ResourceLoadStatistics, DataTaskIdentifierCollision)
     508{
     509    using namespace TestWebKitAPI;
     510
     511    std::atomic<unsigned> serversConnected { 0 };
     512    const char* header = "HTTP/1.1 200 OK\r\nContent-Length: 27\r\n\r\n";
     513
     514    TCPServer httpsServer(TCPServer::Protocol::HTTPSProxy, [&] (SSL* ssl) {
     515        serversConnected++;
     516        while (serversConnected < 2)
     517            usleep(100000);
     518        TCPServer::read(ssl);
     519        TCPServer::write(ssl, header, strlen(header));
     520        const char* body = "<script>alert('1')</script>";
     521        TCPServer::write(ssl, body, strlen(body));
     522    });
     523
     524    TCPServer httpServer([&] (int socket) {
     525        serversConnected++;
     526        while (serversConnected < 2)
     527            usleep(100000);
     528        TCPServer::read(socket);
     529        TCPServer::write(socket, header, strlen(header));
     530        const char* body = "<script>alert('2')</script>";
     531        TCPServer::write(socket, body, strlen(body));
     532    });
     533
     534    _WKWebsiteDataStoreConfiguration *storeConfiguration = [[_WKWebsiteDataStoreConfiguration new] autorelease];
     535    storeConfiguration.httpsProxy = [NSURL URLWithString:[NSString stringWithFormat:@"https://127.0.0.1:%d/", httpsServer.port()]];
     536    WKWebsiteDataStore *dataStore = [[[WKWebsiteDataStore alloc] _initWithConfiguration:storeConfiguration] autorelease];
     537    auto viewConfiguration = adoptNS([WKWebViewConfiguration new]);
     538    [viewConfiguration setWebsiteDataStore:dataStore];
     539
     540    auto webView1 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) configuration:viewConfiguration.get()]);
     541    [webView1 synchronouslyLoadHTMLString:@"start network process and initialize data store"];
     542    auto delegate = adoptNS([DataTaskIdentifierCollisionDelegate new]);
     543    auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) configuration:viewConfiguration.get()]);
     544    [webView1 setUIDelegate:delegate.get()];
     545    [webView1 setNavigationDelegate:delegate.get()];
     546    [webView2 setUIDelegate:delegate.get()];
     547    [webView2 setNavigationDelegate:delegate.get()];
     548    [dataStore _setResourceLoadStatisticsEnabled:YES];
     549    [dataStore _setResourceLoadStatisticsDebugMode:YES];
     550
     551    __block bool isolatedSessionDomain = false;
     552    __block NSURL *prevalentExample = [NSURL URLWithString:@"https://prevalent-example.com/"];
     553    [dataStore _logUserInteraction:prevalentExample completionHandler:^{
     554        [dataStore _setPrevalentDomain:prevalentExample completionHandler: ^(void) {
     555            [dataStore _scheduleCookieBlockingUpdate:^{
     556                isolatedSessionDomain = true;
     557            }];
     558        }];
     559    }];
     560    TestWebKitAPI::Util::run(&isolatedSessionDomain);
     561
     562    [webView1 loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/", httpServer.port()]]]];
     563    [webView2 loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://prevalent-example.com/"]]];
     564
     565    NSArray<NSString *> *messages = [delegate waitForMessages:2];
     566    auto contains = [] (NSArray<NSString *> *array, NSString *expected) {
     567        for (NSString *s in array) {
     568            if ([s isEqualToString:expected])
     569                return true;
     570        }
     571        return false;
     572    };
     573    EXPECT_TRUE(contains(messages, @"1"));
     574    EXPECT_TRUE(contains(messages, @"2"));
     575}
     576
    477577TEST(ResourceLoadStatistics, NoMessagesWhenNotTesting)
    478578{
Note: See TracChangeset for help on using the changeset viewer.