Bug 185483

Summary: iOS 11.3 delays creation of WKWebsiteDataStore and queues setCookie completion handler
Product: WebKit Reporter: Harry Shamansky <hshamansky>
Component: WebKit APIAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: beidson, cdumez, sihui_liu, thorton, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Other   
Hardware: iPhone / iPad   
OS: iOS 11   

Description Harry Shamansky 2018-05-09 12:02:34 PDT
We have the following flow in our app: If navigating to a particular URL in a WKWebView that requires a cookie, cancel the navigation, set a cookie, and in the cookie setter's completion block, load the original URL in the web view.

However, new behavior added by https://github.com/WebKit/webkit/commit/d9d6e5c82c4a74cd573f3f119f166ffcee477b04 delays the creation of the WKWebsiteDataStore such that the completion block is queued until "necessary", and WebKit never actually considers its creation "necessary" since we only load the URL in the completion block. It's essentially a deadlock.

Here's sample code:
```
if (@available(iOS 11.0, *)) {
        [webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie
                                                        completionHandler:^{
            [webView loadRequest:request];
        }];
}
```

This was caused by rdar://problem/33164453 (see also https://bugs.webkit.org/show_bug.cgi?id=176551)

Steps to Reproduce:
Cancel web view navigation, set a cookie with a completion handler that loads the original (canceled) URL. Take no other action on the web view.

Expected Results:
The cookie is set and the completion handler is called.

Actual Results:
The cookie is not set (and the completion handler is not called) until another action is taken on the WKWebView that requires the WKWebsiteDataStore to be initialized.

Version/Build:
Issue affects iOS 11.3+ only. Rarely reproduces on simulator; frequently but not always reproduces on device.

Configuration:
iPhone X 11.3

Filed as rdar://40100673
Comment 1 Chris Dumez 2018-07-25 12:27:50 PDT
Would you be able to provide a minimal test app? Looking at our code, we always call the completion handler right away:
void HTTPCookieStore::setCookie(const WebCore::Cookie& cookie, Function<void ()>&& completionHandler)
{
    auto* pool = m_owningDataStore->processPoolForCookieStorageOperations();
    if (!pool) {
        // FIXME: pendingCookies used for defaultSession because session cookies cannot be propagated to Network Process with uiProcessCookieStorageIdentifier.
        if (m_owningDataStore->sessionID() == PAL::SessionID::defaultSessionID() && !cookie.session)
            WebCore::NetworkStorageSession::defaultStorageSession().setCookie(cookie);
        else
            m_owningDataStore->addPendingCookie(cookie);

        // Calls the completion handler right away if we do not have a pool yet.
        callOnMainThread([completionHandler = WTFMove(completionHandler)]() {
            completionHandler();
        });
        return;
    }

    // This sends an IPC to the network process (starting it if it is not running) and we call the completion handler when the network process has processed the IPC.
    auto* cookieManager = pool->supplement<WebKit::WebCookieManagerProxy>();
    cookieManager->setCookie(m_owningDataStore->sessionID(), cookie, [pool = WTFMove(pool), completionHandler = WTFMove(completionHandler)](CallbackBase::Error error) {
        completionHandler();
    });
}

The code you mention that appends cookies does not delay the call of the completion handler.

Also note that we've made fixes in iOS 12 beta, did you test it?