Modified: trunk/Source/WebCore/ChangeLog (187690 => 187691)
--- trunk/Source/WebCore/ChangeLog 2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebCore/ChangeLog 2015-07-31 23:56:00 UTC (rev 187691)
@@ -1,3 +1,16 @@
+2015-07-31 Chris Dumez <[email protected]>
+
+ Coalesce authentication credential requests
+ https://bugs.webkit.org/show_bug.cgi?id=128006
+ <rdar://problem/16839069>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Export symbol for ProtectionSpace::compare() so it can be called from
+ WebKit2.
+
+ * platform/network/ProtectionSpaceBase.h:
+
2015-07-31 Eric Carlson <[email protected]>
[iOS] use a media-specific user gesture check
Modified: trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h (187690 => 187691)
--- trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h 2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebCore/platform/network/ProtectionSpaceBase.h 2015-07-31 23:56:00 UTC (rev 187691)
@@ -72,7 +72,7 @@
bool encodingRequiresPlatformData() const { return false; }
- static bool compare(const ProtectionSpace& a, const ProtectionSpace& b);
+ WEBCORE_EXPORT static bool compare(const ProtectionSpace&, const ProtectionSpace&);
protected:
WEBCORE_EXPORT ProtectionSpaceBase();
Modified: trunk/Source/WebKit2/ChangeLog (187690 => 187691)
--- trunk/Source/WebKit2/ChangeLog 2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebKit2/ChangeLog 2015-07-31 23:56:00 UTC (rev 187691)
@@ -1,3 +1,40 @@
+2015-07-31 Chris Dumez <[email protected]>
+
+ Coalesce concurrent authentication challenges for the same ProtectionSpace
+ https://bugs.webkit.org/show_bug.cgi?id=147496
+ <rdar://problem/16839069>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Coalesce concurrent authentication challenges for the same ProtectionSpace.
+ Ideally, this would be done in the network layer but short term, this will
+ make sure the user no longer gets repeating authentication dialogs for the
+ same protection space.
+
+ This gets rid of a long-standing bug in WebKit / Safari where visiting a
+ site using HTTP authentication would pop up one authentication dialog for
+ each subresource being loaded from the network (especially when the main
+ resource is loaded from the cache).
+
+ * Shared/Authentication/AuthenticationManager.cpp:
+ (WebKit::canCoalesceChallenge):
+ (WebKit::AuthenticationManager::addChallengeToChallengeMap):
+ (WebKit::AuthenticationManager::shouldCoalesceChallenge):
+ (WebKit::AuthenticationManager::coalesceChallengesMatching):
+ (WebKit::AuthenticationManager::didReceiveAuthenticationChallenge):
+ (WebKit::AuthenticationManager::useCredentialForChallenge):
+ (WebKit::AuthenticationManager::useCredentialForSingleChallenge):
+ (WebKit::AuthenticationManager::continueWithoutCredentialForChallenge):
+ (WebKit::AuthenticationManager::continueWithoutCredentialForSingleChallenge):
+ (WebKit::AuthenticationManager::cancelChallenge):
+ (WebKit::AuthenticationManager::cancelSingleChallenge):
+ (WebKit::AuthenticationManager::performDefaultHandling):
+ (WebKit::AuthenticationManager::performDefaultHandlingForSingleChallenge):
+ (WebKit::AuthenticationManager::rejectProtectionSpaceAndContinue):
+ (WebKit::AuthenticationManager::rejectProtectionSpaceAndContinueForSingleChallenge):
+ (WebKit::AuthenticationManager::AuthenticationManager): Deleted.
+ * Shared/Authentication/AuthenticationManager.h:
+
2015-07-31 Joseph Pecoraro <[email protected]>
Unreviewed parameter name typo fix.
Modified: trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.cpp (187690 => 187691)
--- trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.cpp 2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.cpp 2015-07-31 23:56:00 UTC (rev 187691)
@@ -53,6 +53,12 @@
return ++uniqueAuthenticationChallengeID;
}
+static bool canCoalesceChallenge(const WebCore::AuthenticationChallenge& challenge)
+{
+ // Do not coalesce server trust evaluation requests because ProtectionSpace comparison does not evaluate server trust (e.g. certificate).
+ return challenge.protectionSpace().authenticationScheme() != ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
+}
+
const char* AuthenticationManager::supplementName()
{
return "AuthenticationManager";
@@ -64,7 +70,7 @@
m_process->addMessageReceiver(Messages::AuthenticationManager::messageReceiverName(), *this);
}
-uint64_t AuthenticationManager::establishIdentifierForChallenge(const WebCore::AuthenticationChallenge& authenticationChallenge)
+uint64_t AuthenticationManager::addChallengeToChallengeMap(const WebCore::AuthenticationChallenge& authenticationChallenge)
{
ASSERT(RunLoop::isMain());
@@ -73,12 +79,51 @@
return challengeID;
}
+bool AuthenticationManager::shouldCoalesceChallenge(uint64_t challengeID, const AuthenticationChallenge& challenge) const
+{
+ if (!canCoalesceChallenge(challenge))
+ return false;
+
+ auto end = m_challenges.end();
+ for (auto it = m_challenges.begin(); it != end; ++it) {
+ if (it->key != challengeID && ProtectionSpace::compare(challenge.protectionSpace(), it->value.protectionSpace()))
+ return true;
+ }
+ return false;
+}
+
+Vector<uint64_t> AuthenticationManager::coalesceChallengesMatching(uint64_t challengeID) const
+{
+ AuthenticationChallenge challenge = m_challenges.get(challengeID);
+ ASSERT(!challenge.isNull());
+
+ Vector<uint64_t> challengesToCoalesce;
+ challengesToCoalesce.append(challengeID);
+
+ if (!canCoalesceChallenge(challenge))
+ return challengesToCoalesce;
+
+ auto end = m_challenges.end();
+ for (auto it = m_challenges.begin(); it != end; ++it) {
+ if (it->key != challengeID && ProtectionSpace::compare(challenge.protectionSpace(), it->value.protectionSpace()))
+ challengesToCoalesce.append(it->key);
+ }
+
+ return challengesToCoalesce;
+}
+
void AuthenticationManager::didReceiveAuthenticationChallenge(WebFrame* frame, const AuthenticationChallenge& authenticationChallenge)
{
ASSERT(frame);
ASSERT(frame->page());
+
+ uint64_t challengeID = addChallengeToChallengeMap(authenticationChallenge);
+
+ // Coalesce challenges in the same protection space.
+ if (shouldCoalesceChallenge(challengeID, authenticationChallenge))
+ return;
- m_process->send(Messages::WebPageProxy::DidReceiveAuthenticationChallenge(frame->frameID(), authenticationChallenge, establishIdentifierForChallenge(authenticationChallenge)), frame->page()->pageID());
+ m_process->send(Messages::WebPageProxy::DidReceiveAuthenticationChallenge(frame->frameID(), authenticationChallenge, challengeID), frame->page()->pageID());
}
#if ENABLE(NETWORK_PROCESS)
@@ -86,14 +131,22 @@
{
ASSERT(pageID);
ASSERT(frameID);
+
+ uint64_t challengeID = addChallengeToChallengeMap(authenticationChallenge);
+ if (shouldCoalesceChallenge(challengeID, authenticationChallenge))
+ return;
- m_process->send(Messages::NetworkProcessProxy::DidReceiveAuthenticationChallenge(pageID, frameID, authenticationChallenge, establishIdentifierForChallenge(authenticationChallenge)));
+ m_process->send(Messages::NetworkProcessProxy::DidReceiveAuthenticationChallenge(pageID, frameID, authenticationChallenge, addChallengeToChallengeMap(authenticationChallenge)));
}
#endif
void AuthenticationManager::didReceiveAuthenticationChallenge(Download* download, const AuthenticationChallenge& authenticationChallenge)
{
- download->send(Messages::DownloadProxy::DidReceiveAuthenticationChallenge(authenticationChallenge, establishIdentifierForChallenge(authenticationChallenge)));
+ uint64_t challengeID = addChallengeToChallengeMap(authenticationChallenge);
+ if (shouldCoalesceChallenge(challengeID, authenticationChallenge))
+ return;
+
+ download->send(Messages::DownloadProxy::DidReceiveAuthenticationChallenge(authenticationChallenge, addChallengeToChallengeMap(authenticationChallenge)));
}
// Currently, only Mac knows how to respond to authentication challenges with certificate info.
@@ -108,6 +161,12 @@
{
ASSERT(RunLoop::isMain());
+ for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+ useCredentialForSingleChallenge(coalescedChallengeID, credential, certificateInfo);
+}
+
+void AuthenticationManager::useCredentialForSingleChallenge(uint64_t challengeID, const Credential& credential, const CertificateInfo& certificateInfo)
+{
AuthenticationChallenge challenge = m_challenges.take(challengeID);
ASSERT(!challenge.isNull());
@@ -129,6 +188,12 @@
{
ASSERT(RunLoop::isMain());
+ for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+ continueWithoutCredentialForSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::continueWithoutCredentialForSingleChallenge(uint64_t challengeID)
+{
AuthenticationChallenge challenge = m_challenges.take(challengeID);
ASSERT(!challenge.isNull());
AuthenticationClient* coreClient = challenge.authenticationClient();
@@ -146,6 +211,12 @@
{
ASSERT(RunLoop::isMain());
+ for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+ cancelSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::cancelSingleChallenge(uint64_t challengeID)
+{
AuthenticationChallenge challenge = m_challenges.take(challengeID);
ASSERT(!challenge.isNull());
AuthenticationClient* coreClient = challenge.authenticationClient();
@@ -163,6 +234,12 @@
{
ASSERT(RunLoop::isMain());
+ for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+ performDefaultHandlingForSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::performDefaultHandlingForSingleChallenge(uint64_t challengeID)
+{
AuthenticationChallenge challenge = m_challenges.take(challengeID);
ASSERT(!challenge.isNull());
AuthenticationClient* coreClient = challenge.authenticationClient();
@@ -180,6 +257,12 @@
{
ASSERT(RunLoop::isMain());
+ for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
+ rejectProtectionSpaceAndContinueForSingleChallenge(coalescedChallengeID);
+}
+
+void AuthenticationManager::rejectProtectionSpaceAndContinueForSingleChallenge(uint64_t challengeID)
+{
AuthenticationChallenge challenge = m_challenges.take(challengeID);
ASSERT(!challenge.isNull());
AuthenticationClient* coreClient = challenge.authenticationClient();
Modified: trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.h (187690 => 187691)
--- trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.h 2015-07-31 23:50:01 UTC (rev 187690)
+++ trunk/Source/WebKit2/Shared/Authentication/AuthenticationManager.h 2015-07-31 23:56:00 UTC (rev 187691)
@@ -73,8 +73,17 @@
bool tryUseCertificateInfoForChallenge(const WebCore::AuthenticationChallenge&, const WebCore::CertificateInfo&);
- uint64_t establishIdentifierForChallenge(const WebCore::AuthenticationChallenge&);
+ uint64_t addChallengeToChallengeMap(const WebCore::AuthenticationChallenge&);
+ bool shouldCoalesceChallenge(uint64_t challengeID, const WebCore::AuthenticationChallenge&) const;
+ void useCredentialForSingleChallenge(uint64_t challengeID, const WebCore::Credential&, const WebCore::CertificateInfo&);
+ void continueWithoutCredentialForSingleChallenge(uint64_t challengeID);
+ void cancelSingleChallenge(uint64_t challengeID);
+ void performDefaultHandlingForSingleChallenge(uint64_t challengeID);
+ void rejectProtectionSpaceAndContinueForSingleChallenge(uint64_t challengeID);
+
+ Vector<uint64_t> coalesceChallengesMatching(uint64_t challengeID) const;
+
ChildProcess* m_process;
typedef HashMap<uint64_t, WebCore::AuthenticationChallenge> AuthenticationChallengeMap;